Published: 23 Mar 2011
By: Dustin Davis

An introduction to Aspect Oriented Programming (AOP) and PostSharp.

Contents [hide]

What is Aspect Oriented Programming?

"Aspect Oriented Programming is a programming paradigm which aims to increase modularity by allowing the separation of cross-cutting concerns." - Wikipedia

What does the above quote actually mean? It means that AOP allows you as a developer to focus on writing important code by not having to deal with the mess of cross-cutting concerns. AOP can also take the pain out of writing boiler plate code and repetitive code by automating the implementation.

What are cross-cutting concerns?

The Separation of Concerns principal states that a concern is any piece of interest or focus in a program. Think about it in terms of a layered architecture with the layers being UI, Business, Service and Data. Each one of these layers is its own concern. These layers are "horizontal".

The UI layer is only concerned with display and user interaction and not with database connectivity; as such, the data layer is not concerned with determining if a user is eligible for a car loan (business rules). When you design your code you usually break up these concerns into their own modules (classes, assemblies, etc).

Logging, security, error handling and caching are also concerns but where do they fit in to this layered architecture? The answer is everywhere. These concerns are "vertical" or "cross-cutting" which means they touch each layer. UI needs logging and error handling just as the other layers do too.

Why would you use Aspect Oriented Programming?

In simple terms, AOP allows you to write a block of code and inject it at certain points in your code automatically which results in faster development times, consistency, maintainability and cleaner code. Following the Don't Repeat Yourself (DRY) principal is easy using AOP because you write code once and only once. No copy & paste.

Scenario:

Problem: You're writing an application and you need to log exceptions. This is not a unique problem to solve but is an incredibly trivial part of development.

Old Solution: Wrap a try/catch around each method that requires logging and then add the logging code to the catch block.

AOP Solution: Create an aspect which contains the logging code. Apply the aspect to each method requiring logging.

In this scenario both the solutions are very similar but what impact does each solution have on the code? How scalable, clean, consistent, reliable and maintainable are each solution?

Table 1: Advantages of an AOP-based solution.

 

Old Solution

AOP Solution

Scalability

Not scalable at all. Requires writing code constructs each time the functionality is required. As more methods are added, more code has to be written.

Extremely scalable. Logging can be automatically applied to new methods as they are added with no extra work or thought by the developer.

Cleanliness

Can be clean depending on the size and complexity of the method. Adds at least 7 extra lines of code per method.

Extremely clean because you're not adding any code to the methods.

Consistency

Can be consistent depending on techniques used, but not guaranteed due to repetitive implementation by the developer.

Extremely consistent because the code is coming from a single source and implemented automatically, not by the developer.

Reliability

As the redundancy increases the reliability decreases. Developers can forget and make mistakes.

Very reliable since the code comes from and is maintained in a single location and distributed automatically.

Maintainability

Not very maintainable due to multiple points making it difficult and time consuming to implement code changes.

Extremely maintainable because, again, the code is in a single spot. No find/replace required.

Based on this scenario it's clear that the AOP solution is far superior.

How do I use AOP? Introducing PostSharp

To take advantage of AOP in your development you need an AOP framework. The leading AOP framework is PostSharp by SharpCrafters. PostSharp makes implementing AOP very simple and comes with many pre-built aspects that you just stick your code into and you're done.

PostSharp uses plain .NET attributes that you build out and apply to targets such as assemblies, classes, methods and properties. PostSharp gives you full control of how and where your aspects are applied.

How does it work? PostSharp does its work at build time after the compiler has generated the IL from your C# (or VB, if you're a devil) to produce the final result using MSIL rewriting techniques. PostSharp is based on the PostSharp SDK which is the most advanced assembly transformation platform available so you can be sure that the results are correct and consistent.

PostSharp not only allows you to specify exact targets for your aspects but also allows you to specify at which level to apply them. For example, you could apply the logging aspect from our scenario above to each method individually or you could apply it only on the containing class and let PostSharp apply to the methods automatically which saves you lines of code and time. Some aspects need a greater scope like our logging aspect and will need to be applied to all classes in a project. To fulfill this requirement you can add an assembly level declaration which tells PostSharp to automatically apply the aspect to all methods in all classes.

With the assembly level declaration you no longer have to think about adding logging when adding new classes or methods because it will automatically be injected by PostSharp at build time.

For more information on PostSharp you can visit SharpCrafters.com

Example

For this example we're going to look at how easy it is to start using PostSharp, creating an aspect and applying it to targets explicitly and implicitly while solving a real world problem.

Problem

There are many times where an exception will occur at the bottom of the call stack that will bubble up to a caller higher in the stack that just swallows it. Swallowed exceptions can't be logged or fixed. This commonly happens when taking advantage of the using statement, especially when working with WCF proxies.

Our example code shows how easily this can happen even in the simplest of code. After recognizing the problem, we will use AOP to help us solve this issue.

Project Setup

If you have not done so already, download and install the latest PostSharp 2.0. Once that's done start a new console application project from Visual Studio and add a reference to PostSharp. If you can't find it in the GAC you can browse to it under the install folder \Reference Assemblies\.NET Framework 2.0\PostSharp.dll

Main code

Replace the code in the program.cs file with the following code block

The output of this will be

But wait, only one exception was logged! That's because the other exception was swallowed by the using statement. Such a potentially huge problem can be solved with the simplest application of AOP using PostSharp.

Creating your first aspectAdd a new class to your project called LoggingAspect.cs and add the following code

Note

All aspects require the 'serializable' attribute; you'll receive a compiler error if you don't decorate your aspects.

Our aspect is nothing more than an attribute that inherits from OnExceptionAspect which PostSharp was nice enough to provide for us to handle all the nasty stuff we don't need to worry about. All we have to do is override a single method OnException and populate it with the code we want to use to do error logging. For this example we just output the info to the console.

Note

The LoggingAspect(AttributeExclude=true)] decoration is required for this example. We're telling PostSharp not to include this class when applying the LoggingAspect attribute. If you don't include the decoration you will receive a build error if PostSharp tries to apply the aspect to the aspect class. It could result in a stack overflow at runtime if it were allowed.

Applying the aspect

There many ways in which we can apply our aspect. To start, we'll add it explicitly to the method we know is throwing the swallowed exception. Decorate the TestMethod declaration our new attribute

Now when you run this code you will see that both exceptions are now being logged.

Scaling your solution

We could stop there and call it a day, but why not be consistent and apply our new logging code to all methods? This can be done by decorating each method in the class with our attribute; but that can get messy and less maintainable if there were 20+ methods in our class. Remove the attribute from TestMethod and move it to the TestClass declaration

PostSharp will see that the class is decorated with our aspect attribute and automatically apply it to all methods in the class for us. If you run the updated code the output will be

The output shows duplication for the Dispose method exception. Our aspect logs the error before it bubbles up to the try/catch. Any new methods added will automatically receive our logging declaration. You can refactor the code to remove the redundant try/catch in the main method.

Our example project is as simple as it gets but in the real world you could potentially have hundreds of classes. Decorating each class with our logging aspect just isn't desirable. Thankfully, PostSharp allows us to apply aspects across the assembly.

Remove the attribute from TestClass and open the AssemblyInfo.cs under the Properties folder in the project. At the bottom add the following line

This declaration tells PostSharp to apply our logging aspect to all types under the ConsoleApplication1 namespace using the wildcard syntax.

When you run the code now you will see the same result as before but the difference is whenever you add a new class it will automatically receive the decoration and PostSharp will propagate to all methods in the class our logging aspect automatically.

Conclusion

You can't beat the automation of applying cross-cutting concerns and it's hard to deny how AOP and PostSharp can improve your development and cut development time. PostSharp has much more power than our simple example. The more you use PostSharp and AOP the more uses you will find for it.

<<  Previous Article Continue reading and see our next or previous articles Next Article >>

About Dustin Davis

Dustin is a Microsoft C# MVP, Pluralsight author and producer of c0deporn.

This author has published 3 articles on DotNetSlackers. View other articles or the complete profile here.

Other articles in this category


Android for .NET Developers - Location and Maps
In Windows Phone and iOS getting the current position of the device in terms of latitude and longitu...
Android for .NET Developers - Using Web Views
In this article, I'll show a native app that contains a web-based view. The great news is that HTML ...
Android for .NET Developers - Building a Twitter Client
In this article, I'll discuss the features and capabilities required by an Android application to ta...
Developing a Hello World Java Application and Deploying it in Windows Azure - Part II
In this article we will see the steps involved in deploying the WAR created in the first part of thi...
Ref and Out (The Inside Story)
Knowing the power of ref and out, a developer will certainly make full use of this feature of parame...

You might also be interested in the following related blog posts


Functional programming - F# and Erlang read more
Joel Spolsky: Indigo won't enable a new class of applications read more
Pipelines, Policy and Aspects read more
Top
 
 
 

Please login to rate or to leave a comment.