First look at Postsharp AOP framework for .NET

At the Software Craftsmanship 2010 conference I met Gael Fraiteur of Sharpcrafters, he had given a talk on Aspect Oriented Programming AOP.Since the conference I have had a chance to look at his Postsharp AOP product for .NET.

I decided to do a quick spike project for a tender I have been working on, the requirement is to add a security model to an existing .NET assembly. Usually this would have entailed adding some security logic at the start of each public method to implement the security model. Using AOP I hoped I would be able to get the same effect by adding an attribute to the classes/methods, hopefully making the changes easier to read and quicker to develop.

So I have the following business logic I wish to added security too. All I did was add the [Security] attribute to the business logic method

public class BusinessLogic

{

    IDataProvider data;

 

    public BusinessLogic(IDataProvider data)

    {

        this.data = data;

    }

 

    [Security]

    public DataRecord GetItem(int customerId)

    {

        Debug.WriteLine("BusinessLogic.GetItem");

        return this.data.GetItemFromDB(customerId);

    }

}

So what is in the AOP attribute? Basically I use the AOP framework to intercept the method call, and before the method is invoked I make a call to a factory method to get an instance of the security provider and check if I have the rights to run the method.

[Serializable]

 public class SecurityAttribute :MethodInterceptionAspect

 {

     public override void OnInvoke(MethodInterceptionArgs args)

     {

         Debug.WriteLine("SecurityAttribute.OnInvoke");

 

         // this assumes we know the type of arguement and that we can 

         if (MembershipProviderFactory.GetProvider().CanCurrentUserViewThisItem((int)args.Arguments[0]) == true)

         {

             Debug.WriteLine("SecurityAttribute.OnInvoke: We have rights to view");

             base.OnInvoke(args);

         }

         else

         {

             Debug.WriteLine("SecurityAttribute.OnInvoke: We dont have rights to view");

         }

     }

 }

As it was a spike project I did not bother to write the security provider (or the DB provider for that matter). I used Typemock Isolator to fake it all, so my tests were as shown below. I found this way of working much quicker for my purposes.

/// <summary>

  /// test for both the success and failure paths of the attribute

  /// </summary>

  [TestClass]

  public class Tests

  {

      [Isolated]

      [TestMethod]

      public void When_the_membership_provider_gives_access_the_data_is_returned()

      {

          // arrange

 

          // create a fake objects

          var fakeIMembershipProvider = Isolate.Fake.Instance<IMembershipProvider>();

          var fakeISqlProvider = Isolate.Fake.Instance<ISqlProvider>();

 

          // create real objects

          var fakeData = new DataRecord();

          var bl = new BusinessLogic(fakeISqlProvider);

 

          // Set that when we call the factory method we get the fake membership system

          Isolate.WhenCalled(() => MembershipProviderFactory.GetProvider()).WillReturn(fakeIMembershipProvider);

                      // Set when we call the DB layer we get the fake object

          Isolate.WhenCalled(() => fakeISqlProvider.GetItemFromDB(0)).WillReturn(fakeData);

          // Set that we are allowed to see the item

          Isolate.WhenCalled(() => fakeIMembershipProvider.CanCurrentUserViewThisItem(0)).WillReturn(true);

 

          // act

          var actual = bl.GetItem(1);

 

          // assert

          Assert.AreEqual(fakeData, actual);

          Isolate.Verify.WasCalledWithExactArguments(() => fakeISqlProvider.GetItemFromDB(1));

      }

 

      [Isolated]

      [TestMethod]

      public void When_the_membership_provider_does_not_give_access_the_data_is_returned()

      {

          // arrange

 

          // create a fake objects

          var fakeIMembershipProvider = Isolate.Fake.Instance<IMembershipProvider>();

          var fakeISqlProvider = Isolate.Fake.Instance<ISqlProvider>();

 

          // create real objects

          var fakeData = new DataRecord();

          var bl = new BusinessLogic(fakeISqlProvider);

 

          // Set that when we call the factory method we get the fake membership system

          Isolate.WhenCalled(() => MembershipProviderFactory.GetProvider()).WillReturn(fakeIMembershipProvider);

          // Set when we call the DB layer we get the fake object

          Isolate.WhenCalled(() => fakeISqlProvider.GetItemFromDB(0)).WillReturn(fakeData);

          // Set that we are not allowed to see the item

          Isolate.WhenCalled(() => fakeIMembershipProvider.CanCurrentUserViewThisItem(0)).WillReturn(false);

 

          // act

          var actual = bl.GetItem(1);

 

          // assert

          Assert.AreEqual(null, actual);

          Isolate.Verify.WasNotCalled(() => fakeISqlProvider.GetItemFromDB(1));

      }

 

  }

This all work beautifully and I have to say this was nice and straight forward to code. The code looks clean and using Reflector the generated code is OK tool.

My only worries are

  1. That of performance, but after looking at the code I can’t see that the AOP framework generated code is any great deal less efficient that me adding security methods calls in all the business method. Using Postsharp would certainly require much less repetitive coding. In my spike the security factory strikes me as the bottleneck, but this is my problem, not the frameworks, and can be addressed with a better design pattern to make sure it is not created on every method call.
  2. I can see complexity appearing depending on handling the parameters being passed between the attribute and method being invoked. In my spike I need to know order of the parameters so I could pass the correct one to my security methods, however again I don’t see this as being a major stumbling block, the framework could provide something I am unaware of or I just need to write few forms of the security aspect constructor.

So will I be using Postsharp? I suppose immediately it depends if I win this tender, but I have to say I like what I saw from this first usage.

One Reply to “First look at Postsharp AOP framework for .NET”

  1. Hi Richard! Thank you for blogging about PostSharp. I think this will answer your two worries: Instead of using OnMethodInvocationAspect, try using OnMethodBoundaryAspect and implement OnEntry. The resulting code is much smaller, because the aspect only injects some call before the method; it does not actually hook the whole method. Then, consider a design where the “securable” object is the “this” instance, and not the first argument. I have no idea is this is doeable for your design, but if it is, then OnMethodBoundary does not need to pass the whole set of arguments to this aspect, and it results in further performance enhancement. Another way to improve the aspect would be to annotate each parameter with a custom attribute specifying required permissions. The aspect could check the presence of these custom attributes (typically in method CompileTimeValidate so no reflection is used at run time). Another want you may want to test, if you separate interface from implementation, is whether it makes sense to apply the aspect on the interface or on the implementation. You can do both. I hope these suggestions will help you on your path from “getting started” to production-ready aspects! -gael

Comments are closed.