(Print this page)

Aspect-Oriented Programming (AOP) applied to .Net using PostSharp
Published date: Sunday, September 29, 2013
On: Moer and Éric Moreau's web site

Are you paid based on the number of lines you write in a day? I hope not.

A very well know software development principle know as DRY (Don’t Repeat Yourself) preaches for the least number of lines possible leading to better, more readable code, and easier to maintain.

One way of achieving the DRY principle is by using Aspect-Oriented Programming (AOP).

If you are interested in writing better code (meaning less code) and discover a free tool helping you achieving this goal, read on.

Why AOP?

This paradigm strongest point is the separation of concerns (a method should not do more than a single thing). That means not only that methods should be short but should only do one thing. Take any of your average method. Does it executes more than one thing? Chances are that the answer is yes. I am also a culprit, I have many of these multi-concerns methods. If you answered no, look again. Don’t you have methods doing logging, changing mouse cursor, calculating some stuff … ah you just found a few.

Any best practices/principles/paradigms like AOP will often promises:

  • A decrease in development cost
  • A decrease in software delivery time
  • A reduction in software defects
  • An increase in application maintainability

It is hard to put real amount (dollar and hours) but I am convinced that it really helps.

So what is an aspect?

Normally, you can see an aspect (the A in AOP) as a wrapper of some code. This wrapper does a single thing (answering the single responsibility principle). This wrapper is using the decorator pattern to attach that wrapper to another method providing additional behavior to that method by adding code at compile time.

An example of this is the code you are adding to all the methods to change the cursor to an hour glass and back to default in many methods.

The demo code

This month demo code has been created with Visual Studio 2013 RC (available to MSDN subscribers). VB and C# code is available from the same solution. The same code would work exactly the same from Visual Studio 2010 and/or 2012.

The free tool

You can achieve AOP without any tools but you would have to reinvent the wheel. The good thing is that a version of that wheel is free. The current version works with at least VS 2010, 2012, and 2013.

The tool I want to introduce is PostSharp from SharpCrafters. To start with AOP, the free express version is working. You need to fill a form to receive a key for the PostSharp Express version. If you want to push the paradigm further, you will need to convince your boss to spend some money to buy a better version.

After you installed the latest version, when you will open Visual Studio, you should see a new dialog titled “PostSharp Tutorials” which is a list of links of tutorials, screen casts and videos to help you learn quickly the skills to fully benefit the tool. A PostSharp Exlorer should also appear to help you navigate the aspects you have created.

A first example demonstrating OnMethodBoundatryAspect

The “Hello world” example of PostSharp is often logging. This example is used to demonstrate the 4 method boundaries aspect (entry, exit, success, exception). For example, this code only has one real line of code (playing the beep sound) and adding some tracing code to see what is happening:

Private Sub btnExample1_Click(sender As Object, e As EventArgs) Handles btnExample1.Click
    Trace.WriteLine("Method Entry")
    Try
        Media.SystemSounds.Beep.Play()
        Trace.WriteLine("Method Success")
    Catch ex As Exception
        Trace.WriteLine("Method Exception")
    Finally
        Trace.WriteLine("Method Exit")
    End Try
End Sub

Wouldn’t it be nice if we could write only 1 line of code but still keep the tracing facility? This is exactly what AOP is about. Of course you will write the tracing code somewhere but the code won’t be mixed with the real code and the same code/aspect will be available to many other methods throughout your application.

We first need to enable PostSharp in our project. Create a new project (I created a Windows Forms project) and from the Solution Explorer, right-click your project and select “Add PostSharp to project” and click next.

Then you can create a new class that will contain the code of your aspect. This class needs to inherit from OnMethodBoundaryAspect. The code read as follows:

<Serializable()>
Public Class AspectMethodBoundary
    Inherits OnMethodBoundaryAspect

    Public Overrides Sub OnEntry(ByVal args As MethodExecutionArgs)
        Trace.WriteLine(String.Format("OnEntry - {0} - {1}",
    args.Method.DeclaringType.Name,
    args.Method.Name))
    End Sub

    Public Overrides Sub OnException(ByVal args As MethodExecutionArgs)
        Trace.WriteLine(String.Format("OnException - {0} - {1}",
                args.Method.DeclaringType.Name,
                args.Method.Name))
    End Sub

    Public Overrides Sub OnExit(ByVal args As MethodExecutionArgs)
        Trace.WriteLine(String.Format("OnExit - {0} - {1}",
                args.Method.DeclaringType.Name,
                args.Method.Name))
    End Sub

    Public Overrides Sub OnSuccess(ByVal args As MethodExecutionArgs)
        Trace.WriteLine(String.Format("OnSuccess - {0} - {1}",
                 args.Method.DeclaringType.Name,
                 args.Method.Name))
        If (args.ReturnValue IsNot Nothing) Then
            Trace.WriteLine(String.Format("Value returned = {0}",
                args.ReturnValue.ToString()))
        End If
    End Sub

End Class

As you can see, we are overriding 4 methods to attach to the 4 method boundaries. In this sample, the code simply trace the code much like it was done in the initial example (without AOP). It also shows you that you get a bit of the context (like the method from which the code is called).

Once you have that class, you need to attach it to the method you want. PostSharp offers a couple of methods. The easiest one is to use an attribute (because OnMethodBoundaryAspect from which you inherits is derived from the Attribute class itself). This method here does the same thing as the previous example (playing a beep sound while tracing the method boundaries):

<AspectMethodBoundary()>
Private Sub btnExample1AOP_Click(sender As Object, e As EventArgs) Handles btnExample1AOP.Click
    Media.SystemSounds.Beep.Play()
End Sub

Isn’t it nicer? And now that you have that class, you can reuse it everywhere you need by simply adding the attribute in front of the method.

Handling Exceptions

If you have a generic way of handling errors, you can create one (or more) OnExceptionAspect class(es). More than one is required if you want to handle specific type (ie DivideByZero) with a special class. This is an example of an exception aspect class:

<Serializable()>
Public Class AspectException
    Inherits OnExceptionAspect

    Public Overrides Sub OnException(ByVal args As MethodExecutionArgs)
        Trace.WriteLine(String.Format("Exception type : {0}", args.Exception.GetType().Name))
        Trace.WriteLine(String.Format("Message : {0}", args.Exception.Message))
        Trace.WriteLine(String.Format("Stack Trace : {0}", args.Exception.StackTrace))
    End Sub

End Class

There are 2 important things to notice here:

  • The OnException event of the OnMethodBoundaryAspect will run even if you are handling the error this way (so your method can have more than one attribute)
  • If you have a try … catch exception handler in your method, both exception aspect are ignored (because code wise, your exception is handled and the method is not returning an exception

One last example

The last sample I will show here is called the AspectLocationInterception. This aspect does not apply to methods but to properties (or fields or members).

You are probably now familiar with methods such as OnPropertyChanged that need to fire when the value of a property is modified. If you are writing data binding code, this is mandatory. It can be a pain to modify your existing code to support that behavior.

AOP can help once again in this pattern.

Check this code:

<Serializable()>
Public Class AspectLocationInterception
    Inherits LocationInterceptionAspect

    Public Overrides Sub OnGetValue(ByVal args As LocationInterceptionArgs)
        'if the current value is null and the property is a string, assign a default value
        If (args.GetCurrentValue() Is Nothing AndAlso args.Location.PropertyInfo.PropertyType = GetType(String)) Then
            args.SetNewValue("default")
        End If

        Trace.WriteLine(String.Format("Get Value of property {0} is {1}",
            args.LocationName, args.GetCurrentValue()))

        args.ProceedGetValue()
    End Sub

    Public Overrides Sub OnSetValue(ByVal args As LocationInterceptionArgs)
        Dim current As String
        If (args.GetCurrentValue() Is Nothing) Then
            current = "<<NULL>>"
        Else
            current = args.GetCurrentValue().ToString()
        End If

        Trace.WriteLine(String.Format("Set Value of property {0} from {1} to {2}",
            args.LocationName, current, args.Value))

        args.ProceedSetValue()
    End Sub

End Class

This class overrides 2 methods which execute code whenever the getter or the setter of the attached property is required. This can help you add auditing code, setting default, calling OnPropertyChanged, …

One special thing to notice here is the call to ProceedGetValue and ProceedSetValue. If you don’t call these methods, the actual action of getting and setting the values will be short-circuited by your code and you will never get the correct behavior. These 2 lines are very important (and very easy to forget!).

This is an example of how we can use it:

<AspectException>
 Private Sub btnException_Click(sender As Object, e As EventArgs) Handles btnException.Click
     Dim i As Integer = 0
     Dim j As Integer = 10
     Dim k As Integer = CInt(j / i)
 End Sub

 <AspectLocationInterception>
 Private DummyProperty As String

 <AspectLocationInterception>
 Private DummyInteger As Nullable(Of Integer)

 Private Sub btnLocationInterceptionAspect_Click(sender As Object, e As EventArgs) Handles btnLocationInterceptionAspect.Click
     Dim x As String = DummyProperty

     DummyProperty = "Eric"
     DummyProperty = "Moreau"

     x = DummyProperty

     Dim y = DummyInteger
 End Sub

Seeing what is really happening behind the curtains

To do is magic, PostSharp adds some code at compile time. Basically, it adds code that calls the overridden methods at the correct place. This is why you will see an extra step when you build your project. To really see the impact, you should use tools like .Net Reflector from RedGate or JustDecompile from Telerik. These tools will show you exactly how your code is modified.

Debugging

Even if PostSharp is doing magic by inserting code you didn’t directly write for a particular method, you can debug aspects like any other code by setting breakpoints, using the watch windows, ... You won’t be able to see difference while stepping through your code.

Want to learn more?

Right from within Visual Studio, using the PostSharp Tutorials dialog, you have access to a bunch of help.

Pluralsight also has at least 2 good courses prepared by Donald Belcham on that topic:

  • Aspect Oriented Programming in .Net: this course really explains what is AOP, how it can be achieved through Interceptors or IL Code Weaving
  • PostSharp Fundamentals: this course explains how to install the tool (not very complicated) and how to use the tool to implement AOP in our application

Conclusion

Everybody I know is trying hard to write good code. AOP helps achieving that goal.

PostSharp is one great tool to add to your toolbox helping you writing better code.

There is a lot more AOP and PostSharp can do for your code. I strongly encourage you to try to add these concepts to your application and push further if you find it useful.


(Print this page)