Archive

Download demo project source code

Today we’re going to look at two interception aspects, MethodInterceptionAspect and LocationInterceptionAspect. Due to the nature of these aspects we will break it into two parts. Today we’ll focus on using them and tomorrow we’ll look under the hood and cover chaining.

Interception

Interception aspects are a bit different from the other aspects we’ve looked at. OnExceptionAspect and OnMethodBoundaryAspects essentially wrap the original method body while interception aspects actually replace the method body with a call to the aspect, then moves the original body elsewhere. A simple diagram will help to visualize the process.

image

There are many beneficial processes that can be implemented using interception such as wait/retry, automatic thread delegation, lazy loading and validation.

MethodInterceptionAspect: Adding Multi-Thread Support

Our demo project has a problem of freezing the UI when doing a search. To fix this we must move the call to retrieve the data from the UI thread into its own thread. But, when dealing with the UI, controls cannot be accessed by any thread other than the thread they were created. This is a problem because we are updating a list control with the results of our query. We would get a cross-thread exception if we just moved the whole process to a new thread. We have to make sure that controls are updated on the correct thread.

Add a new file called WorkerThread.cs and add the following code

[Serializable]
public class WorkerThread : MethodInterceptionAspect
{
    public override void OnInvoke(MethodInterceptionArgs args)
    {
        BackgroundWorker bw = new BackgroundWorker();
        bw.DoWork += new DoWorkEventHandler(
            (object sender, DoWorkEventArgs e) =>
            {
                args.Proceed();
            }
        );

        bw.RunWorkerAsync();
    }
        
}

Now add a new file called UIThread.cs and add the following code

[Serializable]
public class UIThread : MethodInterceptionAspect
{
    private delegate void InvokeDelegate();

    public override void OnInvoke(MethodInterceptionArgs args)
    {
        Form main = (Form)args.Instance;

        if (main.InvokeRequired)
        {
            main.BeginInvoke(new Action(args.Proceed));
                
        }else {
            args.Proceed();
        }
    }
}

Our WorkerThread aspect is going to move our method call into a worker thread and execute it so our UI will no longer freeze. UIThread will take the method call and invoke it on the UI thread if it isn’t already on the UI thread so that we don’t receive cross-thread exceptions.

Open the ContactManager.cs code behind and apply the WorkerThread aspect to UpdateContactList() and UIThread to PopulateContactsList().

[WorkerThread]
private void UpdateContactList()
{
…
}

[UIThread]
private void PopulateContactsList(IQueryable contacts)
{ 
…
}

UpdateContactList() is where our query is called from so we want this to run in its own thread as to not interfere with the UI. PopulateContactList() handles manipulation of the control so we have to have the operations done on the UI thread.

Now run the application. As expected, the UI no longer locks up when doing a search.

MethodInterceptionAspect.OnInvoke

MethodInterceptionAspect provides a virtual method, OnInvoke, for us to implement. This method is called in place of the target method call. It is here where we determine if and how the target method is going to be invoked. We do this using the provided MethodInterceptionArgs.

MethodInterceptionArgs

MethodInterceptionArgs provides us with a few things such as access to the arguments passed to the method, the return value, the instance on which the method is being invoked and the method info just as we saw with MethodExecutionArgs when using OnMethodBoundaryAspect.

Since OnInvoke is called instead of the target method, MethodInterceptionArgs also provides ways to continue or change the invocation of the target method

MethodInterceptionArgs.Proceed

The body of the target method is moved into a new method which we can call using MethodInterceptionArgs.Proceed(). As in our threading aspects we made a call to MethodInterceptionArgs.Proceed() inside of our delegate to continue the invocation of the original method on our new thread. Execution will continue passing in the arguments held in MethodInterceptionArgs.Arguments and storing the return value in MethodInterceptionArgs.ReturnValue.

MethodInterceptionArgs.Invoke

When changes to the invocation are required, we can use the MethodInterceptionArgs.Invoke() method to pass in a different set of arguments to the target method.

LocationInterceptionAspect

Whereas the name MethodInterceptionAspect implies its usage, LocationInterceptionAspect does not. LocationInterceptionAspect is meant to be used on properties and fields. Just in case you’re wondering, the PostSharp documentation explains the ‘Location’ part of the name as

…called locations because they [fields & properties] both have the semantics of a slot where a value can be stored and retrieved.

How does it work?

LocationInterceptionAspect uses a pattern similar to the MethodInterceptionAspect which is replacing the body of the getter and setter methods (remember, in .Net properties are turned into a get and set method at compile-time) and replacing it with a call to the aspect’s OnGetValue and OnSetValue methods respectively.

After reading that last paragraph you might be thinking how that is supposed to work on fields (which don’t have getters and setters). When aspects based on LocationInterceptionAspect are applied to fields, they are turned into properties of the same name, scope and visibility as the original field.

Simple example

To clear up any confusion, let’s go through a trivial example. We’ll build an aspect and a simple class with a single property to demonstrate. We’ll start with the aspect.

[Serializable]
public class DemoAspect : LocationInterceptionAspect
{
    public override void OnGetValue(LocationInterceptionArgs args)
    {
        Debug.WriteLine("Get interception by aspect on " + args.LocationName);
        args.ProceedGetValue();
    }

    public override void OnSetValue(LocationInterceptionArgs args)
    {
        Debug.WriteLine("Set interception by aspect on " + args.LocationName);
        args.ProceedSetValue();
    }
}

All we’re doing is writing to the console when we reach a specific point in the process. Now let’s write a test class and apply our aspect.

public class TestClass
{
    private int _myProperty;
    [DemoAspect]
    public int MyProperty 
    {
        get { Debug.WriteLine("Get MyProperty"); return _myProperty; }
        set { Debug.WriteLine("Set MyProperty"); _myProperty = value; } 
    }

    public void Test()
    {
        MyProperty = 1; //Set the property value
        int x = MyProperty; //Get the property value
    }
}

With the aspect applied to our property, any call to the getter or setter will be intercepted and our aspect will take over. The output from calling the Test method on our class will be

Set interception by aspect on MyProperty
Set MyProperty
Get interception by aspect on MyProperty
Get MyProperty

LocationInterceptionAspect: IoC Resolution

One of the great uses I’ve found for LocationInterceptionAspect is lazy loading. Lazy loading can be used to initialize an object only when it’s first requested. Initialization can be a simple new-up or it can also be from an IoC container. The advantages of using an aspect to lazy load from an IoC container are

1. Fields & properties do not have to be public.

2. IoC ignorance. Cleanliness as the IoC specific code is no longer in the class.

What you need

Before you start, you will need to install an IoC container. We’re going to use StructureMap which you can download here. If you’re not familiar with IoC containers, that’s ok. We won’t cover what and why concerning IoC containers, but we will walk through setting up StructureMap and using it. Once you’ve downloaded StructureMap, reference it in the demo project.

Build It

The first thing we need to do is to register a type with the IoC container. We’ll just do this in the Main method in Program.cs

static void Main()
{
	ObjectFactory.Initialize(x =>
	{
		x.For(typeof(IContactRepository)).Use(typeof(InMemoryDataStore));
	});

	Application.EnableVisualStyles();
	Application.SetCompatibleTextRenderingDefault(false);
	Application.Run(new ContactManager());
}

All we’re doing is telling the container that whenever we request a type of IContactRepository, we want to get back an instance of InMemoryDataStore class. Simple as that.

Now we build our aspect. Add a new file called IoCResolution.cs and add the following code

[Serializable]
public class IoCResolution : LocationInterceptionAspect
{
    public override void OnGetValue(LocationInterceptionArgs args)
    {
        args.ProceedGetValue();
        if (args.Value == null)
        {
            object obj = ObjectFactory
.GetInstance(args.Location.PropertyInfo.PropertyType); args.Value = obj; args.ProceedSetValue(); } } }

Lazy load needs to happen when the field/property is requested for read so we implement the OnGetValue method to do our work. We start off by making a call to args.ProceedGetValue which will populate args.Value with the current value of the field/property. If args.Value is null then we request a new instance of the property type from the IoC container and then we set args.Value with our new object. A call to args.ProceedSetValue to finalize the change and we’re done.

Now that our aspect is done we need to make some small changes to ContactManager.cs code behind. First, apply our new aspect to the declaration of the contactRepository and then remove the instantiation of contactRepository from the ContactManager constructor.

[IoCResolution]
IContactRepository contactRepository;
private string searchCriteria = string.Empty;

public ContactManager()
{
	InitializeComponent();
}

Notice Visual Studio puts a blue squiggle under contactRepository to show that its default value will always be null (this is because Visual Studio does not detect an instantiation anywhere).

Go ahead and run the application. As expected, the application makes queries using contactRepository even though we have not explicitly instantiated it.

LocationInterceptionAspect: OnGetValue, OnSetValue

When building aspects based on LocationInterceptionAspect you’ll implement OnGetValue and/or OnSetValue to intercept a get request or set request respectively. Just with MethodInterceptionAspect, the body of the getter and setter are moved to a binding and is replaced with a call to the aspect’s OnGetValue from the getter or OnSetValue from the setter.

LocationInterceptionArgs

Both methods give you access to LocationInterceptionArgs which you will use to manipulate the invocation and the field/property.

LocationInterceptionArgs.GetCurrentValue

Gets the current value of the field/property by invoking the next node in the chain.

LocationInterceptionArgs.ProceedGetValue

Invokes the Get accessor of the next node in the chain. If a single interception aspect is applied, then the body of the getter will be invoked. This method stores the field/property value in LocationInterceptionArgs.Value.

LocationInterceptionArgs.SetNewValue

Sets the field/property to a different value by invoking the next node in the chain.

LocationInterceptionArgs.ProceedSetValue

Invokes the Set accessor of the next node in the chain. If a single interception aspect is applied, then the body of the setter will be invoked. Then new field/property value is set to the value LocationInterceptionArgs.Value.

LocationInterceptionArgs.Index

Index is provided when the property takes parameters. This usually means an indexer. Index is of type arguments and can be iterated over to get the index values passed. This is not for properties of an array or collection type.

LocationInterceptionArgs.Instance

Instance is a reference to the instance from which the invocation is occurring. This property is null if the field or property is static.

LocationInterceptionArgs.Location

Location contains all of the reflection data for the field/property. A LocationInfo wraps a PropertyInfo or FieldInfo.

LocationInterceptionArgs.Value

In the OnGetValue method, args.Value is null until a call to ProceedGetValue(). After ProceedGetValue() returns, args.Value will contain the current value of the field/property. In the OnSetValue method, args.Value will contain the proposed value provided by the caller.

Conclusion

Now that we went over two great examples of interception, we need to understand what happens under the hood, especially when multiple interception aspects are combined on a single target. Tomorrow we’ll grab our shovels and dig deep into how PostSharp implements our interception aspects.

 

self573_thumb[1]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

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