Archive for the ‘PostSharp’ Tag

Validating attribute usage with PostSharp Aspects

This post expands on my previous article on PostSharp. If you haven’t already, read it here

Most of January has flown by with just one post, effectively shooting down my resolution to blog more often. In my defence, I have to state that I’ve just moved on to newer pastures, with all the re-settling in that involves.

Apart from that, I also spent a few hours twiddling with the Jasema sources, so I do have something to post about at least. 🙂

The .net attribute architecture supports an Attribute Usage definition, which is itself an attribute that can be applied to attributes. AttributeUsageAttribute determines whether said attribute can be applied to fields, methods, classes, assemblies, or any combination thereof. This allows you to identify, at compilation time, whether the attributes you have specified are used correctly, which is great.

There are situations, however, where you might want to enforce some more detailed constraints on an attribute; for example, you might want to make sure that it is only used by classes that implement a given interface, or check what parameters have been defined for it.

It is possible to implement this as a runtime check within the attribute itself, however this is not always a very elegant solution. If you check the constraints every time the attribute is invoked in some way, you’re incurring a performance hit, however slight. If one considers that PostSharp aspects may be called every time data changes in a given field, or every time a method (or even any method in an assembly is called), this may add up to quite a bit, depending on what sort of checking you’re doing.

By making this sort of check at run time, you’re also depriving yourself of compile time checking. Even if you have unit tests in place to make sure you catch incorrect behaviour. it can still take time to run the suite; wouldn’t it be a lot nicer if the compiler could be instructed to raise an error when an attribute is given the wrong parameters, or is used with the wrong sort of class?

While PostSharp aspects don’t allow you to give such instructions to the compiler, they do allow you to do something that’s so similar that the difference, to someone like me, is purely academic (so, flame me). These aspects define an OnCompileValidate method, which can be overridden in your custom aspects.

The PostSharp compile-time weaver calls these methods while weaving your aspects into the code, so you can place your validation there; this gives you the advantage of having checks run once only (hence, without impact on executing code). Consider the source below:

         
public override bool CompileTimeValidate(System.Reflection.MethodBase method) 
{ 
    if (string.IsNullOrEmpty(fieldName)) 
        throw new InvalidOperationException( 
            string.Format( 
                "ListContentChangeRecorderAttribute requires the name of a field which implements IList. Failed on {0}.{1}", 
                method.DeclaringType.FullName, 
                method.Name));  

    MemberInfo[] matchingFields = method.DeclaringType 
        .FindMembers( 
            MemberTypes.Field, 
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, 
            this.MemberFilter, 
            fieldName);  

    if (matchingFields.Length < 1) 
        throw new InvalidOperationException( 
            string.Format( 
                "ListContentChangeRecorderAttribute could not find field {0}.{1}", 
                method.DeclaringType.FullName, 
                fieldName));  

    // Determine whether the type that defines the field implements the requested interface. 
    if (!AttributeHelper.ImplementsInterface(((FieldInfo)matchingFields[0]).FieldType, typeof(IList))) 
        throw new NotSupportedException(string.Format( 
            "{0}.{1} does not implement IList.", 
            matchingFields[0].DeclaringType.FullName, 
            fieldName));  

    return base.CompileTimeValidate(method); 
} 

This code, from the custom attributes controlling undo/redo functionality in Jasema v2 (coming soon), runs a few checks on the arguments provided for the attribute at construction: first, it makes sure that the field name argument is not empty, and that the field specified there is an actual existing field in the class which declares the method decorated with this attribute. Finally, using some helper code, it makes sure that the field implements IList, a requirement imposed on it by the logic of the aspect. This sort of checking would take some performance away from the application if it was to run repeatedly, but in this way, it only ever needs to run once – since attribute arguments must be constants, you can safely assume they won’t change after compilation.

Note that although CompileTimeValidate returns a bool type, I’m throwing an exception rather than returning false if the check decides there is something wrong. This is a matter of personal preference. The default behaviour for the weaver appears to be a silent failure; that is, if an aspect fails its validation check by returning false, it is simply omitted. Since I used aspects for a specific reason, I’d much rather have them ring all sorts of bells and raise all sorts of alarms if something is wrong, rather than failing silently and leaving you to scratch your head wondering why your masterfully crafted, world conquering AOP application is not doing what you thought it was supposed to do.

Mind you, the silent failure behaviour was probably introduced to allow the use of PostSharp‘s multicast aspect functionality (like applying an aspect to all methods in an assembly starting with an “F”). This would have been rather unwieldy if it broke the build every time it encountered a situation it didn’t quite support.

So in my case here, for example, I can’t multicast this aspect, but that’s perfectly ok by me because I only intend to use it explicitly. If you think you need to have an attribute capable of multicasting safely, then simply have it return false on failure. You may also be able to get the best of both worlds by making sure that all the classes that can support your attribute have a similar name pattern, but personally that’s where I start going glassy eyed and start drifting off into massively-overlong-classname induced nightmares.

AOP using PostSharp LAOS

Recently, I came across PostSharp, an excellent open source framework for .net. Among the great set of toys which it brings along is LAOS, an Aspect Oriented Programming solution which works very neatly.

Aspect oriented programming is quite a tricky subject to explain in short, so I won’t. While it’s an oversimplification, for the purposes of this post, we will just say that it is a technique where you intercept the control flow as it passes from one block to another, and attach non-default behaviour at these points.

PostSharp provides a mechanism which lets you define attributes to specify this behaviour; you can then decorate an assembly, class, method or field with these attributes. The specific methods you overload will then be triggered accordingly.

As an example, we’re going to add a logger to a method. Yes, it’s pretty boring – 99.99% of the AOP discussions on the web use this scenario as an example. However, I just want to demonstrate how to use these attributes, so no need to rock the boat yet. (If you’re feeling adventurous, visit Manageability for a couple of ideas on what else you can do with AOP).

Let’s say that we want to write a log message every time that an exception is thrown from a method. Since we’re going to use this attribute to handle something that has to do with a method, we’re going to use the OnMethodBoundaryAspect attribute as a base. Among others, this attribute exposes an OnException method, which is just what we need:


onexceptionsource.gif

Like all interception methods exposed by OnMethodBoundaryAspect, OnException accepts a MethodExecutionEventArgs parameter. This gives us access to a lot of useful fields, among others, the name of the method being executed before interception (and all its reflected details), any parameters that were passed to the method, and the full details of the exception. This is especially handy when trying to re-create an exception.

Note the value being set in eventArgs.FlowBehavior. FlowBehavior.Continue tells the application to digest the exception and go on. Not, I must say, the smartest thing to do in all cases; in fact, I’d be dead set against finishing such an intercept this way in most cases. It’s been set that way for the purposes of the example application, where I want and expect an exception to be thrown half-way.

One other possible value of FlowBehaviour which I would like to mention briefly is the Return value. This makes the intercept digest the exception in the same way as Continue, but also allows us to set the MethodExecutionEventArgs.ReturnValue property. In this way, we can return a default value after an exception.

To actually make our new attribute DO something, we have to apply it to a method. We have a number of ways we can do this. If we want, we can specifically apply the attribute to a method (the parameter in the attribute is a constructor parameter for the attribute – refer to the source code attached):

decoratedmethod.gif

We can also apply an attribute to all methods in a class:

decoratedclass.gif

Even more neatly, we can specify an expression that identifies a selection of methods within a class. For example,

decoratedclasswithtarget.gif

The named property tells the attribute that it should apply to all methods and fields in the decorated class where the name starts with “MyLogged”.

Yet another option is to specify the attribute at an assembly level… but if you plan to do that, you really should move on to the actual PostSharp documentation 😛

The source code extends some more methods from the OnMethodBoundaryAspect attribute. You will need to install PostSharp to build the code.

kick it on DotNetKicks.com