Archive

Download demo project source code

Welcome to week 2 of PostSharp Principles. As we move forward we’ll continue to explore the features of PostSharp. We still have a lot to cover and just like last week, we’re going to explore two more aspects provided by PostSharp and we’ll look at what is going on under the hood as we go.

Before we get any deeper into PostSharp, it’s important to understand how PostSharp implements your aspects especially when multiple aspects are applied to a single target. Today we’ll have a look at how PostSharp implements OnMethodBoundaryAspect when applied to a method.

Getting Started

If you have not done so, you will need to download demo project source code and you will also need to download and install a copy of ILSpy. You are welcome to use Reflector as the two tools are very similar.

Example

Continuing with the demo project from last week, let’s look at the GetByName method in the InMemoryDataStore.cs file.

public IQueryable GetByName(string value)
{
    var res = _contactStore.Where(c => c.FirstName.Contains(value) 
|| c.LastName.Contains(value)); if (res.Count() < 1) { ThrowNoResultsException(); } Thread.Sleep(3000); return res.AsQueryable(); }

Since this is a pretty basic method it will be easy to see how PostSharp applies our aspects. Build the project with no aspects applied and then open ILSpy. Once ILSpy is open, browse to the output folder for the demo project and select PostSharpDemo1.exe. Navigate down the namespace tree until you reach the GetByName method in the InMemoryDataStore class.

image

It looks exactly the same as our original code. Let’s apply an aspect and see what changes.

Just for demonstration purposes, let’s build a new aspect based on OnMethodBoundaryAspect. Add a new file called DemoAspect.cs and add the following code

[Serializable]
public class DemoAspect : OnMethodBoundaryAspect
{
    public override void OnEntry(MethodExecutionArgs args)
    {
        Console.WriteLine("OnEntry");
    }

    public override void OnExit(MethodExecutionArgs args)
    {
        Console.WriteLine("OnExit");
    }

    public override void OnSuccess(MethodExecutionArgs args)
    {
        Console.WriteLine("OnSuccess");
    }

    public override void OnException(MethodExecutionArgs args)
    {
        Console.WriteLine("OnException");
    }
}

Apply the aspect to the GetByName method and then rebuild the project. Back in ILSpy, click refresh (you might have to navigate back to the GetByName method). What you see now is much different than before.

image

There is a try/catch/finally added to the method and references to InMemoryDataStore.<>z__Aspects.a0 throughout. Let’s start at the top.

InMemoryDataStore.<>z__Aspects

So what is this? A simple explanation is that this is a helper class that PostSharp creates to hold references to your aspect(s) and an instance of MethodBase for each method in which an aspect is applied. a0 is a reference to an instance of our DemoAspect. Feel free to navigate around using ILSpy.

At the start of our method a call to InMemoryDataStore.<>z__Aspects.a0.OnEntry(null) is made. This is our OnEntry point, before the rest of our method body. Next is a new declaration of our return type called, ‘result’. Our original code didn’t contain a result variable. PostSharp added it because you cannot do a return from a try/catch block in MSIL. This is the same behavior as the C# compiler.

Inside of the try block is our original method body with only a minor change of setting the result variable with our query results. At the end of the try block is a call to InMemoryDataStore.<>z__Aspects.a0.OnSuccess(null) because at this point, all of our code has executed without throwing an error which means it was successful.

The catch block makes a call to InMemoryDataStore.<>z__Aspects.a0.OnException(null) for what should be an obvious reason. An exception has occurred and we wanted to handle that event in our aspect. After our call, the exception is rethrown.

The finally block makes a call to InMemoryDataStore.<>z__Aspects.a0.OnExit(null) because OnExit must always be called even if the method exited with an exception.

At last, the results are returned to the caller.

Adjustments

Let’s make some changes to our aspect. Update the code to the following

[Serializable]
public class DemoAspect : OnMethodBoundaryAspect
{
    public override void OnException(MethodExecutionArgs args)
    {
        Console.WriteLine("OnException");
        args.FlowBehavior = FlowBehavior.Continue;
    }
}

Now we’re only implementing OnException and we’ve changed it to set the FlowBehavior. When an exception occurs, we don’t want to rethrow, just continue on. Rebuild the project and refresh ILSpy.

image

We have a try/catch now instead of a try/catch/finally, but now the catch method is much larger. So what’s going on? Starting our catch block is an instantiation of MethodExecutionArgs and then a call to InMemoryDataStore.<>z__Aspects.a0.OnException(methodExecutionArgs). The reason why there is now a declaration for MethodExecutionArgs is because we need to have access to the properties whereas before, we did not.

Now we come to a switch construct which checks the FlowBehavior property of our MethodExecutionArgs instance. FlowBehavior.Default and FlowBehavior .RethrowException will rethrow while FlowBehavior.Continue (which is what we wanted to do) will return result as it is while FlowBehavior.Return will set the value of result to the value of MethodExecutionArgs.ReturnValue. At the bottom is a catch all jump to the IL_A1 label which will rethrow. This is incase FlowBehavior was set to an unrecognized value.

Play around with different implementations and logic to see how PostSharp changes the resulting code.

As you can see, PostSharp analyzes the code of the aspect and generates only the code that supports the feature actually used by the aspect. This feature is called the aspect optimizer.

Keep in mind that the Starter edition (formerly known as the Community edition) does not include the aspect optimizer, so it may produce much more code for the same aspect.

Conclusion

It is important to know what is happening to your code when you apply aspects. Today we saw an example of OnMethodBoundaryAspect and how the method body is modified to allow the aspect to work. As we continue the series, we’ll look under the hood to see what is going on when dealing with other aspect types and when applying multiple aspects to a single target.

 

self573Dustin 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

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