TSM - PostSharp

Radu Vunvulea - Solution Architect

In the last weeks we discovered together the base principles of Aspect Oriented Programing (AOP). Now is the time to see how we can use at real power the AOP characteristics using PostSharp.

AOP

Before going straight to subject, let"s make a short recap. AOP is a programming paradigm with the main goal of increasing the modularity of an application. AOP tries to achieve this goal by allowing separation of cross-cutting concerns - using interception of different commands or requests.

In the last posts we discovered how we can use AOP using Unity and .NET 4.5 features (RealProxy). Unity gives us the possibility to register actions that can be executed before and after a specific action. The RealProxy class is the base class around all these features that is used by frameworks like Unity to offer this feature.

The biggest difference between RealProxy and a stack that offers us AOP is from the features perspective. Using RealProxy directly will require us to write all the functionality that we need - this can be translated to time, money and more code that we need to maintain (in the end we don"t want to reinvent the wheel).

PostSharp

PostSharp is the first real AOP framework presented in this series of articles. Until now we have looked at different ways in which we can use AOP features, but without using a real and dedicated AOP stack.

I decided to start with PostSharp, because when you need an AOP framework for a real project that is pretty big and complex, you should look at PostSharp first. It is the kind of framework that offers you almost all the features of AOP that you would need.

Usually I compare PostSharp with ReSharper from the point of view of the quality of the product. It is the kind of product that has all the features that you need when you talk about a specific feature.

PostSharp has a lot of features that cannot be discussed in only one article. In the near feature we will study each of these features separately, but for now we will look at the most important features that are around AOP.

Features

The main features of PostSharp are:

Threading Pattern Library - Allow us to control the level of abstraction around threading, detect and diagnose deadlocks, control how actions are executed on different threads and position (foreground or background).

Model Pattern Library - Offers us the full features of AOP using INotifyPropertyChanged interface. All the setup and other things will be taken care of by PostSharp. More complicated behavior can be implemented in a very simple way when we start to use Code Contracts.

Architecture Framework - Gives us the power to validate different aspects of code quality and design, design patterns, core relationships, code analysis and many more.

We saw what the main features of PostSharp are, now let"s inspect the technical part and see how we can add AOP in our project by using PostSharp.

How does it work

The biggest difference between PostSharp and other AOP solutions is how the custom behavior is added. In general this behavior is added at runtime, but not in the case of PostSharp. All the hooks are added at compile time. In this way the performance is not affected too much. Of course, just like in any AOP framework, the performance is affected a little, but in the case of PostSharp, the performance is almost the same as without it.

Basically, PostSharp is a post-processor action, which takes the code that is compiled and modifies it. All the hooks are added at this level. The output from compiler is taken by PostSharp and cooked.

Before and After

The most common use case when AOP is used is to execute a specific action before and after a method of property is called (for example for logging). This can be done very simply using PostSharp with a few lines of code.

The first step is to define the behavior that we want to execute on that specific moment. This can be accomplished by extending OnMethodBoundaryAspect. We can override OnEntry, OnSuccess and OnException. In each of these methods we have access to input parameters, to the result and so on. We can even change the result of the call.

[Serializable] 
public class FooAOPAttribute : OnMethodBoundaryAspect 
{     
    public override void OnEntry(MethodExecutionArgs args) 
    { 
        ... 
    } 
    
    public override void OnSuccess(MethodExecutionArgs args) 
    { 
		...
    } 
	
    public override void OnException(MethodExecutionArgs args) 
    { 
		...
    } 
}

From this moment we can use this attribute to annotate all the methods for which we want to have this feature. Of course we can specify the list of methods not only in this way. We can specify the list of methods from AssemblyInfo.cs, where we can define custom filters for which methods we would like to have this feature.

Code Injection

This feature allow us to add code to our class at runtime. Using a custom attribute or from AssemblyInfo.cs we can inject specific code to our class. For example we can specify that a class implemented a specific interface or inject a specific method of property.

In the below example we can discover how we can inject a specific property to our class:

[Serializable] 
public class FooAOPAspect : InstanceLevelAspect 
{ 
    public string FirstName { get; set; } 
}

[IntroduceMember] 
public string FirstName { get; set; }

[FooAOPAspect] 
public class Student 
{ 

}

The IL code that will be generated will contain the FirstName property inside.

INotifyPropertyChange

When we are working on a desktop or native application, we need to use this interface to be able to receive notification when the value of property is changed (on UI or in code). Usually this is made by implementing the above interface. Not to over complicate the code, a base class is created when the notification functionality is added.

For a small code, this is acceptable, but if you have a complicated application you would add a lot of duplicate code to support this feature.

This problem is resolved by PostSharp for us by NotifyPropertyChangedAttribute. Once we add this property to our class through Smart Tag, we will not need to care about notifications any more. PostSharp will take care of the rest.

[NotifyPropertyChanged] 
public class StudentEdit 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string FullName  
    {  
        get 
		{ 
			return FirstName + LastName); 
		}  
    }     
    public string Email { get; set; } 
}

One thing that I liked was the Transitive Dependencies support. This means that if FirstName value is changed, a notification will be triggered for FullName also.

If we want to add a specific attribute to all our classes from a namespace, we can do this pretty easily by using the multicasting attribute. This is done directly in AssemblyInfo.cs file and will allow us to specify for which classes we need to add a specific attribute. We have the possibility to add filters, exclude specific classes and so on. Of course, this multicasting setup can be done directly from code using IAspectProvider.

The last thing that you should know about this is that you also have other attributes that can be used to ignore specific property or handling notification in a custom way.

Code Contracts

As the name is telling us, Code Contracts give us the possibility to define a contract at code level between the called and method of property that is called. In this way the input validation will not need to be made with a custom IF anymore. It is pretty similar with the custom validation that can be made through ActionFilter and validation attributes in MVC for example. The advantage is that we can define this contract at any level, for example when we are exposing a library API.

The simplest example is NULL checks. Usually when we need to do a NULL check we add an IF in our method/property and throw an exception when value is not NULL. The same thing can be done if we are using the Required attribute.

See below example:

public class Student
{
	public void SetLastName([Required] string newLastName)
	{
		...
	}
}

Without PostSharp we would need to check in the body of the message the value of input and throw an exception. Imagine writing the same code 1.000 times. This kind of attributes can be used also at property or field level. One interesting thing is when we are using it at field value. When we set this value at field or property value, it is not important from where the value is set (for example from another method), the check for NULL will be made.

public class Student
{
	[Required]
	private string _lastName = "Default"

	public void SetLastName(string newLastName)
	{
		_lastName = newLastName;
	}
	
	public string LastName
	{
		get { return _lastName; }
		set { _lastName = value; }
	}

	public void SetFullName(string newFullName)
	{
		...
		_lastName = lastName;
	}
}

A part of default validation actions are already defined. At any time we can define our own custom validation by implementing ILocationValidationAspect. We have ValidateValue method that we need to implement, where we can do our custom validation.

Other features

There are other great features that we have not discussed yet, from the one that allows us to intercept events, composite aspect, code injection, exception handling, security, object persistence and many more. Another feature that I like in PostSharp is the ability to specify that an interface cannot be implemented by other assemblies and can be only used.

I invite all of you to visit PostSharp web site and try it.

Licensing and Costs

There are 3 types of licensing of PostSharp. For individual use, you can successfully use the Express version that is great when you want to learn and understand how PostSharp works.

Additional to Express one we have Professional and Ultimate, which come with other features that can be used with success in production.

Don"t forget that the licensing model is per developer not per products developed. This means that you can use the same license for 1 or 100 projects.

Conclusion

Of course all these features can be implemented by us, but PostSharp offers all these things out of the box. This is a great AOP stack used worldwide, extremely mature and good.