Archive

I thought we would close out this week with a look at the Visual Studio add-ins PostSharp provides for us.

When applying aspects at a class level or assembly level it really hides which methods are going to be affected by an aspect. This is even worse when multiple aspects are applied.

Aspect Browser

image

PostSharp is nice enough to provide a visual aid in determining which methods are affected by which aspects, the Aspect Browser. Select the PostSharp Browser from the View menu.

This window is split into two panes. The top pane, Aspect Browser, contains all aspects in the solution. The grouping is defaulted to namespace but you can adjust this in the settings or by right clicking on an object. In our project there is only one namespace, PostSharpDemo1. If you add a new project and an aspect class, you won't see any changes. Only when the aspect is applied will you see it in the browser.

The Aspect Browser displays information generated by PostSharp at build time so you will have to rebuild your project(s) to see the changes made in your code.

Selecting an aspect will change the Affected Code pane (bottom pane) showing all of the methods affected by the selected aspect. The Affected Code pane is also grouped and sorted by namespace as the default. You can group and sort the Affected Code independently from the Aspect Browser.

Right clicking an item will bring up a context menu that provides options for sorting and grouping as well as going to the definition of that item. Double clicking an item will also take you to the definition.

clip_image004

Method Enhancements

clip_image006

Often we need to see all aspects that a method is being affected by. Again, PostSharp has us covered. If you haven’t noticed by now then take a look at your code. PostSharp enhances methods which are affected by aspects by adding a thick underlining.

Hovering over the method name will bring up a tool-top box that lists not only which aspects affect the method but also at which level the aspect is applied.

The tool-tip provides links that can be used to navigate to the aspect definitions and aspect declarations.

clip_image008

Conclusion

PostSharp is a very sharp tool. These add-ins are our gloves and prevent us from cutting ourselves (maybe). They can have a huge impact when using PostSharp in your development weather you’re testing multicast declarations or troubleshooting aspect issues.

 

self[5][7]Dustin Davis is an enterprise solutions developer and regularly speaks at user groups and code camps. He can be followed on Twitter @PrgrmrsUnlmtd or his blog Programmers-Unlimited.com

Download demo project source code

Today we're going to revisit the OnMethodBoundaryAspect class by building a profiler aspect to help us identify slow executing methods.

As we saw in Day 2 OnMethodBoundaryAspect has 4 methods for us to access specific points in a methods execution

  • OnEntry - Before the execution of the method body
  • OnExit - Always called when a method is done executing even if there was an error
  • OnSuccess - Called only when a method is done executing and there were no exceptions
  • OnException - Called only when a method has stopped executing due to an unhandled exception

Each of these methods provides a MethodExecutionArgs parameter that gives us access to important data.

Method Property

First and most important is the Method property. This is where all of the information about the currently executing method is held. It basically provides all of the information that a System.Reflection.MethodInfo instance would hold. In fact, MethodInfo inherits from MethodBase which can be cast as MethodInfo in case more information is needed (for instance finding the return type).

Instance Property

The Instance property holds a reference to the executing methods object instance and can be reflected to extract the details. Be careful, Instance could be null in certain cases such as when static constructors are executing.

Arguments Property

Since methods usually have arguments, we need to have access to them. MethodExecutionArgs.Arguments provides us with access to those arguments and their values. If you need specific details about the arguments you will need to reflect on them, for instance to display their field values. Otherwise, you can use ToString() to get the value as long as they are value types or types that override the ToString() method.

Exception Property

Exception is nothing more than a standard .NET exception that will contain the current unhandled exception information thrown by the executing method. The Exception property will only be set in the OnException method.

ReturnValue Property

This is self explanatory, really. You can get or set the value that the method is going to return. If you wanted to stop method execution in the OnEntry method, you can set the ReturnValue as needed and then set the FlowBehavior to return. The caller will get back the value specified in ReturnValue.

When inside of the OnExit and OnSuccess methods the ReturnValue will contain the value the method is returning. You can overwrite it or leave it as is.

FlowBehavior Property

There will be times when you need to control what a method does. FlowBehavior is an enum that can be set to control the execution of the method. FlowBehavior not as useful in aspects based on OnMethodBoundaryAspect since it only deals with the start and end of a method. We'll see more of this later when dealing with other aspect types.

As an example, think about our exception aspect we built previously. Policy could demand that a specific exception type should be logged but not rethrown. In this case you should set FlowBehavior to FlowBehavior.Return which would cause the method to return normally to the caller sending back whatever is in ReturnValue.

MethodExecutionTag Property

It can hold anything and is meant to pass state between the advices (for instance between OnEntry and OnSuccess). This is the recommended and preferred way to pass state between the advices. You might be tempted to use an aspect level variable but this approach is not thread safe or reentrant. We’ll look at uses for aspect fields another day.

Building the Profiler Aspect

If you’ve noticed while doing searches, there is a delay before the results are returned. In a small application such as our demo, we could easily eyeball the code to find the offending method. In the real world, we work on complex projects and even projects that we’re not familiar with. Having another tool in our belt can make this type of tasks much simpler to deal with.

Add a new file named ProfilerAspect.cs and add the following code

[Serializable]
[ProfilerAspect(AttributeExclude = true)]
public class ProfilerAspect : PostSharp.Aspects.OnMethodBoundaryAspect
{
    public override void OnEntry(MethodExecutionArgs args)
    {
        args.MethodExecutionTag = Stopwatch.StartNew();
    }

    public override void OnExit(MethodExecutionArgs args)
    {
        Stopwatch sw = (Stopwatch)args.MethodExecutionTag;
        sw.Stop();

        string output = string.Format("{0} Executed in {1} seconds", 
                            args.Method.Name, sw.ElapsedMilliseconds / 1000);

        System.Diagnostics.Debug.WriteLine(output);
    }
}

What we've done is set the MethodExecutionTag with a stopwatch object in OnEntry and then in OnExit we extract that same stopwatch instance from the MethodExecutionTag so we can use it to get the elapsed time it took to execute the method. Finally, we write the details of execution to the output window.

Apply the aspect at the assembly level

[assembly: ProfilerAspect()] 

 

When you run the application you will see that every method reports 0 second execution times...until we search that is. GetByName reports 3 second execution time.

InMemoryDataStore.GetAll Executed in 0 seconds
ContactManager.UpdateContactList Executed in 0 seconds
ContactManager.ContactManager_Load Executed in 0 seconds
InMemoryDataStore.GetByName Executed in 3 seconds
ContactManager.UpdateContactList Executed in 3 seconds
ContactManager.btnSearch_Click Executed in 3 seconds

Obviously we have our culprit. We can now investigate. You’ll appreciate this exercise if you’ve ever written stop watch code to profile methods.

Conclusion

PostSharp does a great job of giving us what we need and the OnMethodBoundaryAspect class is a great starting point for implementing many cross-cutting concerns, but it certainly isn't all we have to work with as you'll see as we continue to dive into the features of PostSharp. While running the application you may have noticed that the performance is significantly slower. This is because we have not yet optimized our aspects. Don’t worry; we’ll be covering aspect optimization on another day.

 

self[5][7]Dustin Davis is an enterprise solutions developer and regularly speaks at user groups and code camps. He can be followed on Twitter @PrgrmrsUnlmtd or his blog Programmers-Unlimited.com

Download demo project source code

Yesterday we started looking at multicasting. Today we’ll go even further with assembly level declarations and how to prevent aspects from being applied.

Assembly Level Declaration

At the highest level we have assembly declarations. This is a powerful feature that allows us to achieve many tasks. Before we explore the details, let’s see it in action. Remove any aspect declarations you have currently.

Note: Depending on your own tastes, you can apply this assembly declaration in any file. Commonly, these are put in the AssemblyInfo.cs file, but they can go anywhere. I recommend putting them in relevant class files to keep the visibility or creating an AspectInfo.cs file to keep them in. Putting them in the AssemblyInfo.cs could be a problem since it's a rarely used file.

[assembly: PostSharpDemo1.MethodTraceAspect()]
namespace PostSharpDemo1
{
    …
}

It can be as simple as that. With no other options this declaration will apply our aspect to every method in every class. Run it and check out the results.

Oops! There was a problem. We can't build the project because PostSharp is trying to apply our aspect to our aspect. The result of this, at least in this case, would be a stack overflow.

Preventing Aspect Application

So how do we prevent an aspect from being applied to certain targets? There are a few ways to achieve this but the easiest and most direct way to explicitly declare the aspect on the target and setting the AttributeExclude property to true. To fix the build errors we have to apply this technique to our aspect class.

[Serializable]
[MethodTraceAspect(AttributeExclude = true)]
public class MethodTraceAspect: OnMethodBoundaryAspect
{
    …
}

Do the same thing for DatabaseExceptionWrapper. Build and run. The output window is filled with every method, constructor and property call made.

The AttributeExclude will work at the class and assembly level as well. Since there are far too many properties in this project to manually add exclusions to each one, we can declare an assembly level exclude

[assembly: PostSharpDemo1.MethodTraceAspect(AttributeExclude = true, AttributePriority = 0, 
            AttributeTargetMemberAttributes = MulticastAttributes.CompilerGenerated)]

The result is the exclusion of property getter and setter methods. When we run the application now, we no longer see them in the output window.

Note: Using the MulticastAttributes.CompilerGenerated will affect more than just properties; anything that gets transformed by the compiler during the build will be affected.

Aspect Priority

We’ve added a new parameter to this declaration called AttributePriority. Application of attributes is undeterministic so there is no guarantee of execution order. If you look at the Warnings when you build the demo project you’ll see warnings from PostSharp about this.

Aspects do different things and the order is which they are applied can affect how they operate. It’s very important to keep this in mind when applying multiple aspects to a target.

We can set the AttributePriority with an integer value to determine the priority. The lower the value is, the higher the priority of the aspect. Higher priority aspects get applied first. Example:

[MethodTraceAspect(AttributePriority = 10)]
[DatabaseExceptionWrapper(AttributePriority = 20)]
public IQueryable GetByName(string value)
{
    …
}

We're telling PostSharp to apply the MethodTraceAspect first and then apply the DatabaseExceptionWrapper second. I used 10 and 20 because it gives better flexibility when you need to apply more aspects. You won’t have to adjust the priority values for each aspect this way. Feel free to use your own system.

Note that using AttributePriority is not considered best practice, because it quickly becomes difficult to manage. We’ll see another day how to address this issue in a clean and robust way.

Assembly Level Part 2

To wrap up this post, let's cover some of the options when declaring assembly declarations. To limit the scope of aspect application we can use the AttributeTargetTypes property to declare a specific type or namespace.

Namespace and Types

[assembly: PostSharpDemo1.MethodTraceAspect(
                       AttributeTargetTypes = "PostSharpDemo1.InMemoryDataStore")]

This declaration will apply the aspect only to the InMemoryDataStore type. The result is the same as decorating the class manually. This is useful when specifying an abstract class because the aspect is applied to all derived classes.

Wildcards
We can also declare wildcards. Specifying an asterisk on part of a namespace will apply the aspect to all types under that namespace and all types in sub namespaces.

[assembly: PostSharpDemo1.MethodTraceAspect(
                       AttributeTargetTypes = "PostSharpDemo1.Data.*")]

Any qualified type under PostSharpDemo1.Data namespace will receive the aspect.

Regular Expressions
PostSharp also lets us use regular expressions to declare target types.

[assembly: PostSharpDemo1 MethodTraceAspect(AttributeTargetTypes = " regex:.*Memory.*")]

Any qualified type with ‘Memory’ in the type name will receive the aspect.

By name
Last but not least, we can specify the exact name of the target. In this case we can declare

[assembly: PostSharpDemo1.MethodTraceAspect(AttributePriority = 10
                            AttributeTargetMembers="GetByName")]

[assembly: PostSharpDemo1.MethodTraceAspect(AttributePriority = 10,
                            AttributeTargetMembers="GetBy*")]

[assembly: PostSharpDemo1.MethodTraceAspect(AttributePriority = 10,
                            AttributeTargetMembers="regex:GetBy.*")]

AttributeTargetMembers is where we declare the name criteria for members.

For example, if we wanted to exclude all properties but using a more specific method than specifying MulticastAttributes.CompilerGenerated we can use the following regular expression to filter any method starting with get_ or set_ since these are what the compiler automatically prefixes getter/setter methods with

[assembly: PostSharpDemo1.MethodTraceAspect(AspectPriority = 10)]
[assembly: PostSharpDemo1.MethodTraceAspect(AspectPriority = 0, 
    AttributeExclude = true, AttributeTargetMembers = "regex:get_.*|set_.*")]

Conclusion

Not by any means did we cover the breadth of applying aspects but you should now have a good grasp on how to get up and running quickly. Being able to declare what will receive an aspect with one single line of code frees up our time and reduces clutter and complexity.

 

self[5][7]Dustin is an enterprise solutions developer and regularly speaks at user groups and code camp. He can be followed on twitter @PrgrmrsUnlmtd or his blog Programmers-Unlimited.com