Click here to Skip to main content
15,867,308 members
Articles / Programming Languages / C# 4.0

Aspect Examples (INotifyPropertyChanged via Aspects)

Rate me:
Please Sign up or sign in to vote.
4.99/5 (79 votes)
5 Jan 2011CPOL30 min read 200K   1.9K   147   107
A look at different Aspect Orientated Programming frameworks.

Introduction

This article is all about Aspect Orientated Programming (AOP).

Here is some tech speak about AOP, from some sources who are more than likely more eloquent than me:

Aspect-oriented programming entails breaking down program logic into distinct parts (so-called concerns, cohesive areas of functionality). All programming paradigms support some level of grouping and encapsulation of concerns into separate, independent entities by providing abstractions (e.g., procedures, modules, classes, methods) that can be used for implementing, abstracting, and composing these concerns. But some concerns defy these forms of implementation and are called crosscutting concerns because they "cut across" multiple abstractions in a program. Logging exemplifies a crosscutting concern because a logging strategy necessarily affects every logged part of the system. Logging thereby crosscuts all logged classes and methods.

All AOP implementations have some crosscutting expressions that encapsulate each concern in one place. The difference between implementations lies in the power, safety, and usability of the constructs provided. For example, interceptors that specify the methods to intercept express a limited form of crosscutting, without much support for type-safety or debugging.

-- http://en.wikipedia.org/wiki/Aspect-oriented_programming

Aspect-Oriented Software Development (AOSD), sometimes just called Aspect-Oriented Programming (AOP), is a new approach to software design that addresses modularity problems that are not handled well by other approaches, including Structured Programming and Object-Oriented Programming (OOP). AOSD complements, but doesn't replace those approaches. Typical enterprise and internet applications today have to address "concerns" like security, transactional behavior, logging, etc. The subsystems that provide these services can be implemented in a modular way. However, to use these services, you must insert the same "boilerplate" code fragments into various places in the rest of the application to invoke these services. This violates the "don't repeat yourself" (DRY) principle and it compromises the overall system modularity, because the same invocation code is scattered throughout the application. For example, if you want to control access to certain services in your application, you could insert authorization-checking boilerplate at the beginning of every method that needs this control. Because this redundant boilerplate appears in many places in the code, it would now be difficult and error prone to modify or replace this security approach later, should that become necessary. Also, your application code is now tangled with code for the security (and probably other) concerns, which both compromises clarity and makes it hard to reuse your code in another context, since you would have to drag along the same security approach, which may not be appropriate. Because concerns like security typically cut across a number of application module boundaries (e.g., classes). We call them cross-cutting concerns. Note that the loss of modularity is at the intersection between the different concerns. AOP restores modularity by developing the cross-cutting concerns, or aspects, in isolation and then combining them with other modules using declarative or programmatic mechanisms that are modular. That is, the points of intersection are defined once, in one place, making them easy to understand and maintain. The other modules require no modifications to be advised by the aspects. This "intersection" process, sometimes called weaving, can occur at build or run time. AOSD weaving is a key innovation that provides very fine grained query and composition semantics. Where traditional code linking has the ability to resolve method and variable names, weaving adds the ability to replace method bodies with new implementations, insert code before and after method calls, instrument variable reads and writes, and even associate new state and behavior with existing classes, typically for adding "mixin" behaviors.

-- What is Aspect-Oriented Software Development?

The Different Type of Aspect Frameworks Out There

There are a few different options available when doing aspect orientated programming (henceforth known as AOP) in .NET. These options/frameworks broadly fall into one of two categories:

Proxy Based AOP Frameworks

Some/a lot of you may have heard of Dependency Injection and even used IOC/Dependency Injection containers such as Castle/Unity/StructureMap/Spring before.

Well, it just so happens that it is quite common for some of these IOC/Dependency Injection containers to use proxies that wrap the real implementation (source object) that is being stored within the IOC/Dependency Injection container. For example, Castle uses a class called DynamicProxy while Unity offers TransparentProxy and VirtualMethodProxy objects. So now that we know that there are some proxies in use (at least in some of these IOC/Dependency Injection containers), it is not so hard to imagine that we can use a proxy to intercept calls to the real object, where by virtual methods/properties (which are just methods really) can be intercepted by the proxy before it calls the real object. Where the user is free to create whatever type of interception code they wish to, which is usually accomplished by implementing a particular interface or extending a certain class etc.

This diagram may help to illustrate how proxy based AOP works:

Image 1

The problem with using this type of AOP framework is that you are forced into using a DI/IOC paradigm which you may not want to use for any other reason than to allow AOP. What that means to you, the developer, is that any type you wish to use AOP with must exist in the IOC/Dependency Injection container and must be resolved from it. This forces a certain type of programming on you, which as I say you may not want. The other problem with proxy based AOP frameworks is the fact that they are using proxies usually means that any method/property you wish to allow to be intercepted must be marked as virtual. Now, you may or may not be able to live with this, but it does open up certain dangers that some other bit of code could mistakenly override these methods/properties due to them being virtual, which could indicate an extension point to someone looking at the code who is not familiar with the overall picture.

One final thing that proxy based AOP frameworks do not seem to be able to cope with is to introduce aspects around backing fields, or around static types, methods, and properties.

IL Weaving Based AOP Frameworks

IL Weaving is an interesting new thing that has only become fairly mainstream (at least I think so anyway) over the past year or two. So what is this IL Weaving of which I speak?

Well, we all know that this is what the normal workflow for .NET code looks like, right?

Image 2

Well, let's now consider the following diagram, which illustrates what happens in IL Weaving based AOP frameworks.

Image 3

Essentially, what happens is that your existing code base is extended by either implementing special interfaces or inheriting from a particular base class, where you can enter your new code. Then at compile time, the new code you entered into these interfaces implementation/classes is obtained, and the IL for the original code and these new bits of code is obtained and literally written out into the Assembly instead of the original IL code.

Pure IL weaving is 100% possible using a not very well known DLL called Mono.Cecil which is part of the Mono project. Although IL weaving is quite advanced, it is something that I urge you all to have an investigative look at, as at least one of the existing AOP frameworks that I have chosen to look at uses Mono.Cecil internally. I will talk about how Mono.Cecil works in some detail when I discuss the AOP frameworks that rely on Mono.Cecil.

The main problem with this type of code is that the workflow of the original code is no longer clear, but saying that, that is also the case with Proxy based AOP frameworks. What IL weaving based frameworks have in their favour is the fact that they are not using a Proxy, they will literally write out new IL, so they do not require any interception method/properties to be virtual at all. This is the case as the IL weaving framework will just grab the original method's IL and pre/post pend to it, or possibly replace it all with new IL. The other neat thing with IL weaving based AOP frameworks (OK, some are more advanced than others) is that you can even introduce new members, fields, events, etc., and there are no problems working with static types, they are just types after all, and as such have IL too.

What Are We Going to Try and Achieve

OK, so now that you have a basic idea of what AOP is about and how some of the existing frameworks out there may provide us, .NET developers, with the tools to write our own aspects, let's briefly talk about what the attached demo app(s) do.

I have provided four different AOP framework demos; where possible I have tried to make them all do the same thing; that has not been possible in all cases, but generally it has been achieved.

So what has been achieved then?

Well, as some of you may know, I am quite into my WPF development, and as such, there is one interface above all others that I implement all the time. This interface is the System.ComponentModel.INotifyPropertyChanged interface (INPC from here on) which looks like this:

C#
namespace System.ComponentModel
{
    // Summary:
    //     Notifies clients that a property value has changed.
    public interface INotifyPropertyChanged
    {
        // Summary:
        //     Occurs when a property value changes.
        event PropertyChangedEventHandler PropertyChanged;
    }
}

Which is typically implemented like this:

C#
public class MainWindowViewModel : INotifyPropertyChanged
{
    private int someProperty;

    public int SomeProperty
    {
        get { return someProperty; }
        set
        {
            someProperty=value;
            RaisePropertyChanged("SomeProperty");
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
           if (PropertyChanged != null)
             PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Now, this interface relies on a magic string being passed into the RaisePropertyChanged method. And as we all know, strings are not refactorable. In fact, the use of the INPC interface is so common that many developers, including myself, have come up with different ways of getting rid of this magic string. Solutions range from using T4 templates, to using Expression Trees, to using StackFrames, believe me I have seen a few implementations.

The thing is, with all these approaches, you still need to do some work. Which got me thinking, wouldn't it be nice if we could just attribute up an auto property to tell if it was an INPC attribute, something like this:

C#
public class MainWindowViewModel : INotifyPropertyChanged
{
    [INPCAttribute]
    public virtual string DummyProp1 { get; set; }

    [INPCAttribute]
    public virtual string DummyProp2 { get; set; }


    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Which got me thinking even more.Well, if I can fire the INPC PropertyChanged event using some aspect orientated programming, perhaps I could even write an aspect that would implement the System.ComponentModel.INotifyPropertyChanged interface automatically for me, which would lead to code like this:

C#
public class DummyModel
{
    [AddINPCAttribute]
    public virtual string DummyModelProp1 { get; set; }

    [AddINPCAttribute]
    public virtual string DummyModelProp2 { get; set; }

    public virtual string DummyModelProp3 { get; set; }
}

OK, this would not suit every property and sometimes you would want to manually control when to fire the INPC event, or add more code in the setter of the property, but for 80%, auto firing INPC events may be more than suitable.

Largely, I have been very successful and managed just that, and that is what the rest of the article is going to talk about.

However, before we carry on, I just wanted to go back to something I mentioned earlier, where I said that I tried to make all the different AOP frameworks do the same thing. Well, I tried, but in some cases, I either lacked the motivation or the skills. I have chosen to evaluate four AOP frameworks, and these, along with what I did with them, is shown in the table below:

AOP FrameworkWhat I Managed to Achieve
Castle
  • Created a property targeting attribute, that when applied to a class that already implements INotifyPropertyChanged will call the INotifyPropertyChanged PropertyChanged event when the property is set
  • Created a property targeting attribute, that when applied to a class that does not implement INotifyPropertyChanged will automatically implement the INotifyPropertyChanged interface and will call the PropertyChanged event when the property with the attribute is set
Unity
  • Created a property targeting attribute, that when applied to a class that already implements INotifyPropertyChanged will call the INotifyPropertyChanged PropertyChanged event when the property is set
  • Globally applied an interception behavior that will cause any intercepted property setter to fire the INotifyPropertyChanged PropertyChanged event when the property is set, if the target type already implements INotifyPropertyChanged
PostSharp (not free)
  • Created a class targeting attribute, that when applied to a class that does not implement INotifyPropertyChanged will automatically implement the INotifyPropertyChanged interface and will call the PropertyChanged event when a property is set
LinFu.AOP *
  • Created a property targeting attribute, that when applied to a class that already implements INotifyPropertyChanged will call the INotifyPropertyChanged PropertyChanged event when the property is set

* Has dependency on Mono.Cecil

Digging Deep Into the Demo Code Examples

The next subsection will outline how the various AOP frameworks that I chose to look at do what I just discussed in the table above.

Castle (Proxy Based)

PriceVersion UsedAvailable From
Free2.5.0.0http://www.castleproject.org/

Castle is an IOC/Dependency Injection Container. Now recall what I said I managed to achieve using Castle.

Objective 1

Created a property targeting attribute, that when applied to a class that already implements INotifyPropertyChanged will call the INotifyPropertyChanged PropertyChanged event when the property is set

Objective 2

Created a property targeting attribute, that when applied to a class that does not implement INotifyPropertyChanged will automatically implement the INotifyPropertyChanged interface and will call the PropertyChanged event when the property with the attribute is set

So now, let's look at how we managed to achieve both of these objectives, starting with Objective 1.

Objective 1, Step 1: Create a INPCAttribute

The firsst step is straightforward; we simply create a standard .NET attribute as follows:

C#
[AttributeUsage(AttributeTargets.Property)]
public class INPCAttribute : Attribute
{
}

It can be seen that nothing much happens in this code; it is just a marker that we will use to mark properties that will need to call the INPC PropertyChanged event when set.

Objective 1, Step 2: Creating an INPC IInterceptor

In Castle, method inception (and remember properties are just methods get_xxxx/set_xxxx) is achieved using a special castle interface called IInterceptor, which for objective 1 can be implemented as follows:

This interceptor is automatically applied to any Type in the ViewModel's namespace, by the ViewModelInstaller (we will see that soon). When this interceptor is called, it will then examine the method (and property changes are just get_xxx()/set_xxx() methods after all), and look for a INPCAttribute, which is a standard Attribute which if found will cause the method invocation to also fire the INPC PropertyChanged event on the target object.

C#
public class NotifyPropertyChangedInterceptor : IInterceptor
{
    #region IInterceptor Implementation

    public void Intercept(IInvocation invocation)
    {
        // let the original call go 1st
        invocation.Proceed();

        if (invocation.Method.Name.StartsWith("set_"))
        {
            string propertyName = invocation.Method.Name.Substring(4);
            var pi = invocation.TargetType.GetProperty(propertyName);

            // check for the special attribute
            if (!pi.HasAttribute<INPCAttribute>())
                return;

            FieldInfo info = invocation.TargetType.GetFields(
                    BindingFlags.Instance | BindingFlags.NonPublic)
                        .Where(f => f.FieldType == typeof(PropertyChangedEventHandler))
                        .FirstOrDefault();

            if (info != null)
            {
                //get the INPC field, and invoke it we managed to get it ok
                PropertyChangedEventHandler evHandler = 
                    info.GetValue(invocation.InvocationTarget) 
                    as PropertyChangedEventHandler;
                if (evHandler != null)
                    evHandler.Invoke(invocation.TargetType, 
                        new PropertyChangedEventArgs(propertyName));
            }
        }
    }
    #endregion
}

Objective 1, Step 3: Using the INPCAttribute on a Target Type

Now that we have a INPCAttribute, all we need to do is apply this INPCAttribute to some target type. In the demo app, this INPCAttribute is applied to the MainWindowViewModel type as follows:

C#
public class MainWindowViewModel : INotifyPropertyChanged
{
    #region Ctor
    public MainWindowViewModel()
    {
        DummyModel = ContainerWiring.Instance.Container.Resolve<DummyModel>(); 
    }
    #endregion

    #region Public Properties
    //Auto properties that will be made into INPC property via
    //NotifyPropertyChangedInterceptor, note that the properties MUST be virtual

    [INPCAttribute]
    public virtual string DummyProp1 { get; set; }

    [INPCAttribute]
    public virtual string DummyProp2 { get; set; }

    public string DummyProp3 { get; set; }

    public DummyModel DummyModel { get; set; }
    #endregion

    #region INPC Implementation

    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

Objective 1, Step 4: Configuring Castle for Inception for MainWindowViewModel

Now that we have a type that makes use of the INPCAttribute, we need to make sure Castle is configured to use it. This is done within the ContainerWiring class as follows:

C#
public class ContainerWiring
{
    #region Data
    private static readonly Lazy<ContainerWiring> instance
        = new Lazy<ContainerWiring>(() => new ContainerWiring());

    private IWindsorContainer container;
    #endregion

    #region Ctor
    private ContainerWiring()
    {
        container = new WindsorContainer();
    }
    #endregion

    #region Public Methods/Properties
    public static ContainerWiring Instance
    {
        get
        {
            return instance.Value;
        }
    }

    public IWindsorContainer Container
    {
        get { return container; }
    }


    public void SetUp()
    {
        container.Install(FromAssembly.This());
    }

    public void TearDown()
    {
        if (container != null)
        {
            container.Dispose();
        }

        container = null;
    }
    #endregion

}

Note: I am using a Lazy<T> singleton approach here, which is my latest favourite way of doing singletons as it is both Lazy and thread safe, and reads well as well, and does not rely on any compiler related tricks.

Mmmm, no mention of any inception code there, just some Setup() method... curious. What actually happens is that the Setup() method is responsible for installing everything that the demo app requires. But what is that actually doing? Well, in Castle, you can inherit from another interface called IWindsorInstaller which when implemented will do whatever you specified in your implementation, and will allow the IWindsorInstaller implementing class to be installed into the Castle container.

The demo app features three installers, two of which I will talk about now, and one I will talk about later.

ViewModelInstaller

Will install inception for any Type that is in the same namespace as the MainWindowViewModel, and that is how we apply inception to the MainWindowViewModel Type we just saw above.

C#
public class ViewModelInstaller : IWindsorInstaller
{
    #region IWindsorInstaller Implementation

    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        //register ViewModels and add interceptors
        container.Register(AllTypes.FromThisAssembly()
            .Where(Castle.MicroKernel.Registration.Component.
            IsInSameNamespaceAs<MainWindowViewModel>())
            .Configure(c => c.LifeStyle.Transient
                        .Interceptors(typeof(NotifyPropertyChangedInterceptor))));
    }

    #endregion
}

InterceptorInstaller

Any custom interceptors must also be installed into the Castle container in order to, well, um, actually intercept anything. So here is the InterceptorInstaller from the demo app.

C#
public class InterceptorInstaller : IWindsorInstaller
{
    #region IWindsorInstaller Implementation

    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(AllTypes.FromThisAssembly().BasedOn<IInterceptor>());
    }

    #endregion
}

Objective 1, Step 5 : Use the MainWindowViewModel

So now we have all the pieces, we just need to make use of this intercepted type. So in the demo app, this is done within MainWindow as follows:

C#
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        MainWindowViewModel viewModel = 
           ContainerWiring.Instance.Container.Resolve<MainWindowViewModel>(); 
        this.DataContext = viewModel;
        (viewModel as INotifyPropertyChanged).PropertyChanged += 
                      MainWindowViewModel_PropertyChanged;
    }

    private void MainWindowViewModel_PropertyChanged(object sender, 
                 PropertyChangedEventArgs e)
    {
        MessageBox.Show(string.Format("{0} property changed " + 
                        "in MainWindowViewModel", e.PropertyName));
    }
}

You can see above that we get the inception enabled MainWindowViewModel from the Castle container, and since the MainWindowViewModel type makes use of the special INPCAttribute, we should end up calling the INPC PropertyChanged event whenever a property is set in the inception enabled MainWindowViewModel Type.

And to prove that works, here is a screenshot of that running:

Image 4

So that was all we had to do to meet Objective 1. Let's now have a look at Objective 2, which just looked like this:

Objective 2

Created a property targeting attribute, that when applied to a class that does not implement INotifyPropertyChanged will automatically implement the INotifyPropertyChanged interface and will call the PropertyChanged event when the property with the attribute is set

Objective 2, Step 1 : Create a AddINPCAttribute

As with objective 1, this first step is straightforward enough; we simple create a standard .NET attribute as follows:

C#
[AttributeUsage(AttributeTargets.Property)]
public class AddINPCAttribute : Attribute
{
}

It can be seen that nothing much happens in this code, it is just a marker that we will use to mark properties that will need to call the INPC PropertyChanged event when set. But this time, the target type will be made to implement the INotifyPropertyChanged interface directly by the Castle Container.

Objective 2, Step 2: Creating an Add INPC IInterceptor

As before, we inherit from the special Castle interface called IInterceptor, but this time, the implementation is very different. We actually want to add the implementation of the INotifyPropertyChanged interface on the target object.

So what we have is this:

C#
public class AddNotifyPropertyChangedInterceptor : IInterceptor
{
    #region Data
    private PropertyChangedEventHandler handler;
    #endregion

    #region IInterceptor Implementation

    public void Intercept(IInvocation invocation)
    {
        string methodName = invocation.Method.Name;
        object[] arguments = invocation.Arguments;
        object proxy = invocation.Proxy;
        bool isINPC = false;

        try
        {
            if (invocation.TargetType != null)
            {
                PropertyInfo realProp = invocation.TargetType.
            GetProperty(invocation.Method.Name.Substring(4));
                isINPC = realProp.HasAttribute<AddINPCAttribute>();
            }
        }
        catch { }

        if (invocation.Method.DeclaringType.Equals(typeof(INotifyPropertyChanged)))
        {
            if (methodName == "add_PropertyChanged")
                StoreHandler((Delegate)arguments[0]);
            if (methodName == "remove_PropertyChanged")
                RemoveHandler((Delegate)arguments[0]);
        }


        if (!ShouldProceedWithInvocation(methodName))
            return;

        invocation.Proceed();

        if (isINPC)
            NotifyPropertyChanged(methodName, proxy);
    }

    #endregion

    #region Protected Methods
    protected void OnPropertyChanged(Object sender, PropertyChangedEventArgs e)
    {
        var eventHandler = handler;
        if (eventHandler != null) eventHandler(sender, e);
    }

    protected void RemoveHandler(Delegate @delegate)
    {
        handler = (PropertyChangedEventHandler)Delegate.Remove(handler, @delegate);
    }

    protected void StoreHandler(Delegate @delegate)
    {
        handler = (PropertyChangedEventHandler)Delegate.Combine(handler, @delegate);
    }

    protected void NotifyPropertyChanged(string methodName, object proxy)
    {
        if (methodName.StartsWith("set_"))
        {
            var propertyName = methodName.Substring(4);

            var args = new PropertyChangedEventArgs(propertyName);
            OnPropertyChanged(proxy, args);
        }
    }

    protected bool ShouldProceedWithInvocation(string methodName)
    {
        var methodsWithoutTarget = new[] { 
        "add_PropertyChanged", "remove_PropertyChanged" };
        return !methodsWithoutTarget.Contains(methodName);
    }
    #endregion
}

It can be seen that we handle Add/Remove of delegates for the INotifyPropertyChanged interface implementation, and we also raise the INPC PropertyChanged event, when a property is set that has our special AddINPCAttribute.

Objective 2, Step 3: Using the AddINPCAttribute on a Target Type

Now that we have a AddINPCAttribute, all we need to do is apply this AddINPCAttribute to some target type. In the demo app, this AddINPCAttribute is applied to the DummyModel type as follows:

C#
public class DummyModel
{
    //Auto properties that will be made into INPC property via
    //AddNotifyPropertyChangedInterceptor

    [AddINPCAttribute]
    public virtual string DummyModelProp1 { get; set; }

    [AddINPCAttribute]
    public virtual string DummyModelProp2 { get; set; }

    public virtual string DummyModelProp3 { get; set; }
}

Notice how this Type does not implement the INotifyPropertyChanged interface at all.

Objective 2, Step 4: Configuring Castle for Inception for DummyModel

Now that we have a type that makes use of the AddINPCAttribute, we need to make sure Castle is configured to use it. This is done within the ContainerWiring class that we saw previously.

C#
public class ContainerWiring
{
    #region Data
    private static readonly Lazy<ContainerWiring> instance
        = new Lazy<ContainerWiring>(() => new ContainerWiring());

    private IWindsorContainer container;
    #endregion

    #region Ctor
    private ContainerWiring()
    {
        container = new WindsorContainer();
    }
    #endregion

    #region Public Methods/Properties
    public static ContainerWiring Instance
    {
        get
        {
            return instance.Value;
        }
    }

    public IWindsorContainer Container
    {
        get { return container; }
    }


    public void SetUp()
    {
        container.Install(FromAssembly.This());
    }

    public void TearDown()
    {
        if (container != null)
        {
            container.Dispose();
        }

        container = null;
    }
    #endregion

}

And as I previously stated, most of the inception code is actually done via IWindsorInstaller, and I already discussed 2 out of 3 of these from the demo app; we just need to discuss the last one, which adds the AddNotifyPropertyChangedInterceptor to the DummyModel type. This is done as follows:

ModelInstaller

Will install inception for any Type that is in the same namespace as DummYModel, and that is how we apply inception to the DummyModel Type we just saw above.

C#
public class ModelInstaller : IWindsorInstaller
{
    #region IWindsorInstaller Implementation

    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        //register ViewModels and add interceptors
        container.Register(AllTypes.FromThisAssembly()
          .Where(Castle.MicroKernel.Registration.Component.
                        IsInSameNamespaceAs<DummyModel>())
          .Configure(c => c.LifeStyle.Transient
                        .Proxy.AdditionalInterfaces(typeof(INotifyPropertyChanged))
                        .Interceptors(typeof(AddNotifyPropertyChangedInterceptor))));
    }

    #endregion
}

Objective 2, Step 5: Use the DummyModel

So now we have all the pieces; we just need to make use of this intercepted type. So in the demo app, this is done within MainWindowViewModel which holds an instance of a DummyModel:

C#
public class MainWindowViewModel : INotifyPropertyChanged
{

    public MainWindowViewModel()
    {
        DummyModel = ContainerWiring.Instance.Container.Resolve<DummyModel>(); 
    }

    .......
    .......
    .......

    public DummyModel DummyModel { get; set; }
    .......
    .......
    .......
}

Which we can listen to INPC PropertyChanged event notification from, in the MainWindow code-behind, as follows:

C#
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        MainWindowViewModel viewModel = 
        ContainerWiring.Instance.Container.Resolve<MainWindowViewModel>(); 
        this.DataContext = viewModel;
        (viewModel as INotifyPropertyChanged).PropertyChanged += 
                      MainWindowViewModel_PropertyChanged;
        (viewModel.DummyModel as INotifyPropertyChanged).PropertyChanged += 
                   DummyModel_PropertyChanged;
    }

    private void MainWindowViewModel_PropertyChanged(object sender, 
                 PropertyChangedEventArgs e)
    {
        MessageBox.Show(string.Format("{0} property changed " + 
                        "in MainWindowViewModel", e.PropertyName));
    }

    private void DummyModel_PropertyChanged(object sender, 
                 PropertyChangedEventArgs e)
    {
        MessageBox.Show(string.Format("{0} property changed " + 
                        "in DummyModel", e.PropertyName));
    }
}

And to prove that works, here is a screenshot of that running:

Image 5

Unity (Proxy Based)

PriceVersion UsedAvailable From
Free2.0.414.0Part of Enterprise Library 5.0

Unity is an IOC/Dependency Injection Container that comes as a standalone application block, but I am using the one that comes with Enterprise Library 5.0.

Now recall what I said I managed to achieve using Unity.

Objective 1

Created a property targeting attribute, that when applied to a class that already implements INotifyPropertyChanged will call the INotifyPropertyChanged PropertyChanged event when the property is set

Objective 2

Globally applied an interception behavior that will cause any intercepted property setter to fire the INotifyPropertyChanged PropertyChanged event when the property is set, if the target type already implements INotifyPropertyChanged.

So now, let's look at how we managed to achieve both of these objectives, starting with Objective 1.

Objective 1, Step 1: Create a Special Inception Enabled Attribute

In Unity, inception can be enabled in a few different ways, but one common way is to inherit from a special Unity attribute, called the HandlerAttribute. HandlerAttribute is an attribute that when inherited from will allow your custom attributes to potentially inject aspects into the method call pipeline. The demo app uses this INPCAttribute which inherits from HandlerAttribute:

C#
[AttributeUsage(AttributeTargets.Property)]
public class INPCAttribute : HandlerAttribute
{
    public override ICallHandler CreateHandler(IUnityContainer container)
    {
        return new INPCHandler();
    }
}

It can be seen that nothing much happens in this code; this code creates another Type, called INPCHandler. So that must be what we should look at next.

Objective 1, Step 2: Creating a Handler for the INPCAttribute

As we just saw, we have a special INPCAttribute which creates a INPCHandler. So what does a INPCHandler look like?

C#
/// <summary>
/// This handler is automatically applied to any Type in the ViewModels 
/// which use the <c>INPCAttribute</c>.
/// When this ICallHandler implementation is called it will then examine 
/// the method (and property changes are just get_xxx()/set_xxx() methods, and look 
/// for a <c>INPCAttribute</c>, which  is a standard Attribute which if found will cause 
/// the method invocation to also fire the NotifyChanged() method on the target object.
/// 
/// See the <c>MainWindowViewModel</c> for an example of this
/// </summary>
public class INPCHandler : ICallHandler
{
    #region ICallHandler Members

    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
    {
        // let the original call go through first, so we can notify *after*
        IMethodReturn result = getNext()(input, getNext);

        if (input.MethodBase.Name.StartsWith("set_"))
        {
            string propertyName = input.MethodBase.Name.Substring(4);
            var pi = input.Target.GetType().GetProperty(propertyName);

            // check for the special attribute
            if (pi.HasAttribute<INPCAttribute>())
            {

                // get the field storing the delegate list that are stored by the event.
                FieldInfo info = input.Target.GetType().BaseType.GetFields(
            BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy)
                    .Where(f => f.FieldType == typeof(PropertyChangedEventHandler))
                    .FirstOrDefault();

                if (info != null)
                {
                    // get the value of the field
                    PropertyChangedEventHandler evHandler = 
            info.GetValue(input.Target) as PropertyChangedEventHandler;
                    // invoke the delegate if it's not null (aka empty)
                    if (evHandler != null)
                        evHandler.Invoke(input.Target.GetType(), 
                new PropertyChangedEventArgs(propertyName));
                }
            }
        }

        return result;
    }

    public int Order
    {
        get
        {
            return 0;
        }
        set
        {

        }
    }

    #endregion
}

It can be seen above that this INPCHandler also inherits from a Unity interface called ICallHandler. It is actually possible using Unity to apply handlers that implement ICallHandler directly. But in this example, the INPCHandler was created by applying the INPCAttribute to some target type. So what does implementing ICallHandler give us? Well, basically, inheriting from ICallHandler gives us the correct pipeline hook to the actual code out aspect. Any ICallHandler implementation will be called at the appropriate time, providing we have configured Unity correctly.

It can also be seen from the above code that we are looking to see if we are in a property setter, and if we are, we check to see if the property we are setting has the special INPCAttribute on it, and if it does, we know we need to call the INPC PropertyChanged event. So we just call it.

Objective 1, Step 3: Using the Special INPCAttribute on a Target Type

Now that we have a INPCAttribute that we can apply that internally makes sure we get a INPCHandler based ICallHandler class, all we need to do is apply this INPCAttribute to some target type. In the demo app, this INPCAttribute is applied to the MainWindowViewModel type as follows:

C#
/// <summary>
/// Simple ViewModel that has auto properties that are made into 
/// INPC based properties by using Unity application block using
/// the <c>INPCAttribute</c> which in turn
/// create a new <c>INPCHandler</c> which
/// will examine turn any auto property adorned with the <c>INPCAttribute</c>
/// into an INPC property
/// </summary>
public class MainWindowViewModel : INotifyPropertyChanged
{
    #region Ctor
    public MainWindowViewModel()
    {
        DummyModel = ContainerWiring.Instance.Container.Resolve<DummyModel>();
    }
    #endregion

    #region Public Properties
        
    //Note that these properties MUST be virtual for Unity inception to work
    //as Unity is using a VirtualMethodInterceptor

    [INPC]
    public virtual string DummyProp1 { get; set; }

    [INPC]
    public virtual string DummyProp2 { get; set; }

    public string DummyProp3 { get; set; }

    public DummyModel DummyModel { get; set; }
    #endregion

    #region INotifyPropertyChanged Implementation
    /// <summary>
    /// Occurs when any properties are changed on this object.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;


    /// <summary>
    /// A helper method that raises the PropertyChanged event for a property.
    /// </summary>
    /// <param name="propertyNames">The names
    ///       of the properties that changed.</param>
    protected virtual void NotifyChanged(params string[] propertyNames)
    {
        foreach (string name in propertyNames)
        {
            OnPropertyChanged(new PropertyChangedEventArgs(name));
        }
    }

    /// <summary>
    /// Raises the PropertyChanged event.
    /// </summary>
    /// <param name="e">Event arguments.</param>
    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, e);
        }
    }
    #endregion
}

Objective 1, Step 4: Configuring Unity for Inception for MainWindowViewModel

Now that we have a type that makes use of the INPCAttribute, we need to make sure Unity is configured to use it. This is done within the ContainerWiring class as follows:

C#
public class ContainerWiring
{
    #region Data
    private static readonly Lazy<ContainerWiring> instance
        = new Lazy<ContainerWiring>(() => new ContainerWiring());

    private IUnityContainer container;
    #endregion

    #region Ctor
    private ContainerWiring()
    {
        container = new UnityContainer();
    }
    #endregion

    #region Public Methods/Properties
    public static ContainerWiring Instance
    {
        get
        {
            return instance.Value;
        }
    }

    public IUnityContainer Container
    {
        get { return container; }
    }


    public void SetUp()
    {

        //register we want Interception
        container.AddNewExtension<Interception>();

        //register types
        container.RegisterType<MainWindowViewModel>();
        container.RegisterType<DummyModel>();

        //Configure Interception

        //Configure MainWindowViewModel to have any virtual methods intercepted
        //which will end up using the INPCHandler
        //due to the use of the INPCAttribute(s) in the
        //MainWindowViewModel type

        //Configure DummyModel to have any virtual methods
        //intercepted using the NonAttributedINPCHandler
        //but only for property setters
        PolicyDefinition policy = container.Configure<Interception>().
            SetInterceptorFor<DummyModel>(new VirtualMethodInterceptor()).
            SetInterceptorFor<MainWindowViewModel>(
              new VirtualMethodInterceptor()).AddPolicy("NotifyPolicy");

    }

    public void TearDown()
    {
        if (container != null)
        {
            container.Dispose();
        }

        container = null;
    }
    #endregion

}

Objective 1, Step 5: Use the MainWindowViewModel

Now we have all the pieces, we just need to make use of this intercepted type. In the demo app, this is done within MainWindow as follows:

C#
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        MainWindowViewModel viewModel = 
          ContainerWiring.Instance.Container.Resolve<MainWindowViewModel>();
        this.DataContext = viewModel;
        (viewModel as INotifyPropertyChanged).PropertyChanged += 
          MainWindowViewModel_PropertyChanged;
    }

    private void MainWindowViewModel_PropertyChanged(object sender, 
                 PropertyChangedEventArgs e)
    {
        string extraInfo = "Note as we are using an HandlerAttribute " +
               "and a blanket PolicyDefinition \r\n " +
               "of * we will get 2 * INPC events for MainWindowViewModel, " +
               "But I am keeping this in to show you the options";

        MessageBox.Show(string.Format(
          "{0} property changed in MainWindowViewModel\r\n\r\n{1}", 
          e.PropertyName, extraInfo));
    }
}

You can see above that we get the inception enabled MainWindowViewModel from the UnityContainer, and since the MainWindowViewModel type makes use of the special INPCAttribute, we should end up calling the INPC PropertyChanged event whenever a property is set in the inception enabled MainWindowViewModel Type.

And to prove that works, here is a screenshot of that running:

Image 6

So that was all we had to do to meet Objective 1. Let's now have a look at Objective 2, which looked like this:

Objective 2

Globally applied an interception behavior that will cause any intercepted property setter to fire the INotifyPropertyChanged PropertyChanged event when the property is set, if the target type already implements INotifyPropertyChanged

Objective 2, Step 1: Creating a Global INPC Handler

So this time the objective is to create a global handler that can be applied to an entire class, and will automatically call the INPC PropertyChanged event whenever a property is set. So for that, we need to implement another Unity ICallHandler which is shown below. Note: this time, there is no checking for any special attribute as soon as we realize we are setting a property, and attempt is made to call the target type's INPC PropertyChanged event.

C#
/// <summary>
/// This handler is used in direct conjuntion with a Unity <c>PolicyDefintion</c> which
/// allows Unity to specify that only property setters
/// will be intercepted using this CallHandler.
/// It makes auto properties fire the NotifyChanged() method
/// on the target object when the property is set.
/// See the <c>DummyModel</c> for an example of this
/// </summary>
public class NonAttributedINPCHandler : ICallHandler
{
    #region ICallHandler Members

    public IMethodReturn Invoke(IMethodInvocation input, 
                         GetNextHandlerDelegate getNext)
    {
        // let the original call go through first, so we can notify *after*
        IMethodReturn result = getNext()(input, getNext);

        if (input.MethodBase.Name.StartsWith("set_"))
        {
            string propertyName = input.MethodBase.Name.Substring(4);
            var pi = input.Target.GetType().GetProperty(propertyName);

            // get the field storing the delegate list that are stored by the event.
            FieldInfo info = input.Target.GetType().BaseType.GetFields(
                BindingFlags.Instance | BindingFlags.NonPublic | 
                BindingFlags.FlattenHierarchy).Where(
                f => f.FieldType == 
                typeof(PropertyChangedEventHandler)).FirstOrDefault();

            if (info != null)
            {
                // get the value of the field
                PropertyChangedEventHandler evHandler = #
            info.GetValue(input.Target) as PropertyChangedEventHandler;
                // invoke the delegate if it's not null (aka empty)
                if (evHandler != null)
                    evHandler.Invoke(input.Target.GetType(), 
            new PropertyChangedEventArgs(propertyName));
            }
        }

        return result;
    }

    public int Order
    {
        get
        {
            return 0;
        }
        set
        {

        }
    }

    #endregion
}

It can be seen above that this NonAttributedINPCHandler also inherits from a Unity interface called ICallHandler. And for this implementation, we intend to apply this globally to a certain target type, by providing Unity with the configuration information to apply it automatically to any property change.

Objective 2, Step 2: We Need a Target Type to Use This Global ICallHandler on

So we have a global ICallHandler that we can apply in Unity whenever a property is set, but we still need a target type to apply it on to. So what does that target type look like? Well, for the demo code, it looks like this:

C#
public class DummyModel : INotifyPropertyChanged
{
    public virtual string DummyModelProp1 { get; set; }

    public virtual string DummyModelProp2 { get; set; }

    public string DummyModelProp3 { get; set; }

    #region INotifyPropertyChanged Implementation
    /// <summary>
    /// Occurs when any properties are changed on this object.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;


    /// <summary>
    /// A helper method that raises the PropertyChanged event for a property.
    /// </summary>
    /// <param name="propertyNames">The names of the properties that changed.</param>
    protected virtual void NotifyChanged(params string[] propertyNames)
    {
        foreach (string name in propertyNames)
        {
            OnPropertyChanged(new PropertyChangedEventArgs(name));
        }
    }

    /// <summary>
    /// Raises the PropertyChanged event.
    /// </summary>
    /// <param name="e">Event arguments.</param>
    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, e);
        }
    }
    #endregion
}

Objective 2, Step 3: Configuring Unity for Inception for DummyModel

Now that we have a type that we want to apply the NonAttributedINPCHandler to, we need to make sure Unity is configured to use it. This is done within the ContainerWiring class as follows:

C#
public class ContainerWiring
{
    #region Data
    private static readonly Lazy<ContainerWiring> instance
        = new Lazy<ContainerWiring>(() => new ContainerWiring());

    private IUnityContainer container;
    #endregion

    #region Ctor
    private ContainerWiring()
    {
        container = new UnityContainer();
    }
    #endregion

    #region Public Methods/Properties
    public static ContainerWiring Instance
    {
        get
        {
            return instance.Value;
        }
    }

    public IUnityContainer Container
    {
        get { return container; }
    }


    public void SetUp()
    {

        //register we want Interception
        container.AddNewExtension<Interception>();

        //register types
        container.RegisterType<MainWindowViewModel>();
        container.RegisterType<DummyModel>();

        //Configure Interception

        //Configure MainWindowViewModel to have any virtual methods intercepted
        //which will end up using the INPCHandler due
        //to the use of the INPCAttribute(s) in the
        //MainWindowViewModel type

        //Configure DummyModel to have any virtual methods
        //intercepted using the NonAttributedINPCHandler
        //but only for property setters
        PolicyDefinition policy = container.Configure<Interception>().
            SetInterceptorFor<DummyModel>(new VirtualMethodInterceptor()).
            SetInterceptorFor<MainWindowViewModel>(
              new VirtualMethodInterceptor()).AddPolicy("NotifyPolicy");

        //Configure PolicyDefinition : Note as we are using
        //an HandlerAttribute and a blanket PolicyDefinition 
        //of * we will get 2 * INPC events for MainWindowViewModel,
        //But I am keeping this in to show you the options
        policy.AddMatchingRule(new PropertyMatchingRule("*", 
                               PropertyMatchingOption.Set));
        policy.AddCallHandler<NonAttributedINPCHandler>();
    }

    public void TearDown()
    {
        if (container != null)
        {
            container.Dispose();
        }

        container = null;
    }
    #endregion

}

Note: that is the entire listing for the ContainerWiring class, so it also includes the previous Unity setup we saw for MainWindowViewModel for objective 1. See how this time we use an instance of the Unity PolicyDefinition, and we specify that any property setter should be matched, and we add a call handler of our NonAttributedINPCHandler handler, which calls the INPC PropertyChanged event on the target object within the caller.

Now, one interesting thing of note here is that, because the MainWindowViewModel also has properties that can be set, it is also included in this blanket setter policy, but it also makes use of the INPCAttribute on two of its properties which we talked about above. Which means when changing either of these two MainWindowViewModel properties that also has the INPCAttribute applied, we will get two INPC PropertyChanged event notifications. One for the INPCAttribute, and one from the globally applied NonAttributedINPCHandler.

For the DummyModel type, this is not the case, as it only uses the blanket setter policy, so only that rule applies.

Objective 2, Step 4: Use the DummyModel

OK, so now that we have this DummyModel type that will have a global Unity ICallHandler applied to it, we just need to use one of these DummyModel classes somewhere. For the demo app, the MainWindowViewModel (itself set for inception) uses a DummyModel as a property as follows:

C#
public class MainWindowViewModel : INotifyPropertyChanged
{
    public MainWindowViewModel()
    {
        DummyModel = ContainerWiring.Instance.Container.Resolve<DummyModel>();
    }

    ......
    ......
    ......
    public DummyModel DummyModel { get; set; }
    ......
    ......
    ......
    ......
    ......

}

So we can also listen to INPC PropertyChanged events from a MainWindowViewModel's DummyModel instance, as follows, in the MainWindow code-behind:

C#
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        MainWindowViewModel viewModel = 
        ContainerWiring.Instance.Container.Resolve<MainWindowViewModel>();
        this.DataContext = viewModel;
        (viewModel.DummyModel as INotifyPropertyChanged).PropertyChanged += 
                              DummyModel_PropertyChanged;
    }


    private void DummyModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        MessageBox.Show(string.Format("{0} property changed " + 
                        "in DummyModel", e.PropertyName));
    }

}

And here is a screenshot to show that working:

Image 7

PostSharp (IL Weaving)

PriceVersion UsedAvailable From
£120-£2202.0.0.0http://www.sharpcrafters.com/postsharp/download

Has a 45 day free trial

Postsharp is a premier league AOP framework, arguably the most mature one on the market, and it is very, very feature rich; some of you may recall that it also used to be free. Unfortunately, all good things come to an end, and now one has to pay for PostSharp, not that much though.

Anyway, if you recall what I said I managed to achieve with PostSharp:

Created a class targeting attribute, that when applied to a class that does not implement INotifyPropertyChanged will automatically implement the INotifyPropertyChanged interface and will call the PropertyChanged event when a property is set.

All that I need to do to achieve this is carry out a few steps.

Step 1: Reference PostSharp

Add a reference to PostSharp.dll.

Image 8

Step 2: Create an Object We Want to Make INPC

For the attached demo app, this looks like this where I am using a special INPC aspect class which is discussed in Step3. Notice below that I am not implementing INPC at all, nor do any of the properties have any attributes on them, and also note that the properties are standard auto properties, and that they are not virtual.

C#
[INPC]
public class MainWindowViewModel
{
    #region Public Properties
    //Note that these properties are NOT virtual
    public string DummyProp1 { get; set; }
    public string DummyProp2 { get; set; }
    public string DummyProp3 { get; set; }
    #endregion
}

Step 3: Implement the INPC Aspect

This is where the real work comes; we now have to implement the actual INPC aspect class, which looks like this:

C#
[Serializable]
[IntroduceInterface(typeof(INotifyPropertyChanged), 
    OverrideAction = InterfaceOverrideAction.Ignore)]
[MulticastAttributeUsage(MulticastTargets.Class, 
    Inheritance = MulticastInheritance.Strict)]
public sealed class INPCAttribute : InstanceLevelAspect, INotifyPropertyChanged
{
    #region Public Properties / Methods

    [ImportMember("OnPropertyChanged", IsRequired = false, 
        Order = ImportMemberOrder.AfterIntroductions)]
    public Action<string> OnPropertyChangedMethod;

    [IntroduceMember(Visibility = Visibility.Family, 
        IsVirtual = true, OverrideAction = MemberOverrideAction.Ignore)]
    public void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this.Instance, 
                    new PropertyChangedEventArgs(propertyName));
        }
    }

    [IntroduceMember(OverrideAction = MemberOverrideAction.Ignore)]
    public event PropertyChangedEventHandler PropertyChanged;

    [OnLocationSetValueAdvice, MulticastPointcut(Targets = MulticastTargets.Property, 
        Attributes = MulticastAttributes.Instance | MulticastAttributes.NonAbstract)]
    public void OnPropertySet(LocationInterceptionArgs args)
    {
        // Don't go further if the new value is equal to the old one.
        // (Possibly use object.Equals here).
        if (args.Value == args.GetCurrentValue()) return;

        // Actually sets the value.
        args.ProceedSetValue();

        this.OnPropertyChangedMethod.Invoke(args.Location.Name);

    }
    #endregion

Now there is a lot going on there, but none of it is beyond us, so let's break it down a bit.

It can be seen below that this aspect not only calls NotifyPropertyChanged whenever a property is set, but also introduces an actual implementation of the INotifyPropertyChanged interface, and also introduces all the events and methods that are required by a INotifyPropertyChanged implementation. This is mainly achieved using the IntroduceMemberAttribute.

And that is pretty much all there is to it. If we run the demo where we have the MainWindow set its DataContext to a MainWindowViewModel, we can indeed see that the MainWindowViewModel is implementing INPC correctly.

C#
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        MainWindowViewModel viewModel = new MainWindowViewModel();
        this.DataContext = viewModel;
        (viewModel as INotifyPropertyChanged).PropertyChanged += 
                       MainWindowViewModel_PropertyChanged;
    }

    private void MainWindowViewModel_PropertyChanged(object sender, 
                 PropertyChangedEventArgs e)
    {
        string extraInfo = 
        "Note as we are using an PostSharp, we simply not " +
        "even have to have virtual properties in our MainWindowViewModel";
        MessageBox.Show(string.Format(
           "{0} property changed in MainWindowViewModel\r\n\r\n{1}", 
           e.PropertyName, extraInfo));
    }
}

Image 9

LinFu.AOP (IL Weaving)

PriceVersion UsedAvailable From
Free1.0.0.0http://www.codeproject.com/KB/cs/LinFuPart6.aspx

As LinFu.AOP internally relies on the Mono.Cecil DLL that I mentioned right back at the start of the article, I thought I would just go through a quick example of how Mono.Cecil works.

How Mono Cecil Works

Suppose I have a type that already implements INPC, and that we have a standard INPC property such as FirstName shown below:

Image 10

And we also have an auto property LastName shown below, which as we can see has some compiler generated bits to it.

Image 11

And we examine the IL for the StartName full INPC property:

Image 12

Compared to the IL for the auto generated LastName property:

Image 13

we can see that they are nearly the same, but we are just missing a few IL instructions:

Image 14

So if we could somehow manage to get in there and introduce these IL instructions, and save the Assembly, both the full INPC property and the auto property should work the same. That is exactly what Mono.Cecil allows us to do, and here is some example code to do just that:

C#
CilWorker MSILWorker = prop.SetMethod.Body.CilWorker;
Instruction ldarg0 = MSILWorker.Create(OpCodes.Ldarg_0);
Instruction propertyName = MSILWorker.Create(OpCodes.Ldstr, prop.Name);
Instruction callRaisePropertyChanged = 
   MSILWorker.Create(OpCodes.Call, raisePropertyChanged);
MSILWorker.InsertBefore(prop.SetMethod.Body.Instructions[0], 
                        MSILWorker.Create(OpCodes.Nop));
MSILWorker.InsertBefore(
   prop.SetMethod.Body.Instructions[
   prop.SetMethod.Body.Instructions.Count - 1],ldarg0);
MSILWorker.InsertAfter(ldarg0, propertyName);
MSILWorker.InsertAfter(propertyName, callRaisePropertyChanged);
MSILWorker.InsertAfter(callRaisePropertyChanged, MSILWorker.Create(OpCodes.Nop));

Obviously, LinFu.AOP does a lot more than this, but it does use Cecil to do it. Which generally works as shown above. I will obviously outline exactly how LinFu does work in much finer detail, but I just felt that this little diversion was worth while.

OK, so now back to LinFu.

How LinFu Works

Anyway, if you recall what I said I managed to achieve with LinFu:

Created a property targeting attribute, that when applied to a class that already implements INotifyPropertyChanged will call the INotifyPropertyChanged PropertyChanged event when the property is set.

All that I need to do to achieve this is carry out a few steps.

Step 1: Create the Aspect Intercepted Project

Unfortunately, I could not seem to get LinFu to work unless I split the project where aspects were to be woven and the aspects themselves into two projects. So I created a project which stored types that would be incepted, and made sure I referenced the correct LinFu DLLs.

Image 15

Step 2: Edit the MSBuild File for the Aspect Intercepted Project

The next thing I had to do was unload the project with the types that would have the aspects woven into them. For the demo app, this means the LinFu.ViewModels project.

Then I had to add the following lines to the MSBUILD file for the project:

XML
<PropertyGroup>
    <PostWeaveTaskLocation>
      C:\Users\WIN7LAP001\Desktop\Downloads\LinFu_Src\LinFu.Aop.Tasks.dll
    </PostWeaveTaskLocation>
  </PropertyGroup>
  <UsingTask TaskName="PostWeaveTask" AssemblyFile="$(PostWeaveTaskLocation)" />
  <Target Name="AfterBuild" Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
    <PostWeaveTask 
      TargetFile="$(MSBuildProjectDirectory)\
                  $(OutputPath)$(MSBuildProjectName).dll" 
      InjectConstructors="true" />
  </Target>

This step is vital, as it points to the PostWeaver Task that LinFu uses to inject the aspects. After you have added this and made it to point to the correct location on your installation, you can reload the project.

Step 3: Marking Up a Class That You Want to be INPC

This is the easy part; we simply need to come up with a simple Attribute that we can use as a marker that is applied to properties, that we can later examine to see if our aspect should fire the PropertyChanged event of the intercepted type.

This attribute simple looks like this:

C#
[AttributeUsage(AttributeTargets.Property)]
public class INPCAttribute : Attribute
{
}

Step 3: Using the INPCAttribute on a Target Type

The next step is to actually use this INPCAttribute on a target type. For the LinFu demo, this will be a MainWindowViewModel type that simply looks like this:

C#
public class MainWindowViewModel : INotifyPropertyChanged
{
    #region Public Properties
    //Auto properties that will be made into INPC property via
    //INPCMethodInvocation, note the properties are NOT virtual

    [INPCAttribute]
    public string DummyProp1 { get; set; }

    [INPCAttribute]
    public string DummyProp2 { get; set; }

    public string DummyProp3 { get; set; }
    #endregion

    #region INPC Implementation

    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

You will notice that for this class, we do actually implement the INotifyPropertyChanged interface, so we are only expecting the LinFu aspect to call the INotifyPropertyChanged interface's PropertyChanged event that is already available within the MainWindowViewModel.

That is all there is to this first LinFu AOP demo project, but next, we need to look at the actual project that contains the aspect. So let's carry on and look at that, shall we?

Step 4: Create the Aspect Weaving Project

As I mentioned in Step 1, I could not seem to get LinFu to work unless I split the project where aspects were to be woven and the aspects themselves into two projects. So I created a project which stored types that would be incepted. We have already created the first of these projects, which is the project which stored types that would be incepted; now we need to create the project that does the actual aspects and will produce the IL woven code.

Let's have a look at this other project. It is a WPF application that needs the following references:

Image 16

Where the LinFu.ViewModels reference is the project we created in Step 1.

Step 5: Create the Inception Code That Will Produce the Modified IL

LinFu uses interfaces for aspects, and has the special interface IInvokeAround which you can implement to have your aspect run when you call a method/property (properties really are methods like get_XXXX/set_XXXX). So what we want is an aspect that will call the INotifyPropertyChanged on a target type which implements the INotifyPropertyChanged PropertyChanged event when a property is set.

Here is the full code for the LinFu.AOP IInvokeAround implementing inception code (it is quite similar to the Castle/Unity code):

C#
public class INPCMethodInvocation : IAroundInvoke
{
    #region IAroundInvoke Members

    public void AfterInvoke(IInvocationContext context, object returnValue)
    {
        if (context.TargetMethod.Name.StartsWith("set_"))
        {
            string propertyName = context.TargetMethod.Name.Substring(4);
            var pi = context.Target.GetType().GetProperty(propertyName);

            // check for the special attribute
            if (!pi.HasAttribute<INPCAttribute>())
                return;


            FieldInfo info = context.Target.GetType().GetFields(
                    BindingFlags.Instance | BindingFlags.NonPublic)
                        .Where(f => f.FieldType == typeof(PropertyChangedEventHandler))
                        .FirstOrDefault();

            if (info != null)
            {
                //get the INPC field, and invoke it we managed to get it ok
                PropertyChangedEventHandler evHandler =
                    info.GetValue(context.Target) as PropertyChangedEventHandler;
                if (evHandler != null)
                    evHandler.Invoke(context.Target.GetType(),
                        new PropertyChangedEventArgs(propertyName));
            }
        }

    }

    public void BeforeInvoke(IInvocationContext context)
    {
        //Not going to do anything before context
    }

    #endregion
}

What then happens in LinFu is that when compilation occurs, the LinFu TaskWeaver MSBUILD task will be run, which will examine any type that has Inception allowed, and will then use the existing type's method IL, and will then grab the IAroundInvoke implementation's XXXXInvoke code and get the IL for that, and it will then form a new Instruction list of IL internally to LinFu, and it will then use the Mono.Cecil DLL's IL Rewriting capabilities to rewrite the Assembly to contain the original method's IL plus the IAroundInvoke implementation's XXXXInvoke IL. So in the case of IAroundInvoke implementation's AfterInvoke(...), we would end up with the original method's IL plus the IAroundInvoke implementation's AfterInvoke IL being emitted to the modified Assembly IL.

Remember, all of this is happening at compile time; it is not a runtime thing; the Assembly is actually modified to have new IL woven into it. This is what Mono.Cecil allows. And that is what LinFu uses internally.

Step 6: Applying the Aspect to a Target Type

All is good so far; we have an aspect which we can apply to a type, we now just need to apply it. Here is how we do that with LinFu.AOP (note: I am using the same Lazy<T> type singleton that I showed earlier). Let's see how we wire up inception in LinFu. This is done in the demo app in a single class called Inception, nothing special about that name, it's just one I picked, and here is the full code for that class:

C#
public class Inception
{
    #region Data
    private static readonly Lazy<Inception> instance
        = new Lazy<Inception>(() => new Inception());
    #endregion

    #region Ctor
    private Inception()
    {
    }
    #endregion

    #region Public Methods/Properties
    public static Inception Instance
    {
        get
        {
            return instance.Value;
        }
    }
  
    public void SetUp()
    {
        var mainWindowViewModelProvider = 
            new SimpleAroundInvokeProvider(new INPCMethodInvocation(),
                c => c.TargetMethod.DeclaringType == typeof(MainWindowViewModel));

        AroundInvokeRegistry.Providers.Add(mainWindowViewModelProvider);
    }
    #endregion
}

All we do is set up a new INPCMethodInvocation interceptor which we created in step 5, and apply that to the MainWindowViewModel type. Quite simple really... right?

Step 7: Using the Aspected Type

Now that we have all the pieces of the puzzle, all we need to do is get ourselves one of these intercepted MainWindowViewModel types, and make sure it works.

So here is how we do that:

C#
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        var viewModel = new MainWindowViewModel();
        this.DataContext = viewModel;
        (viewModel as INotifyPropertyChanged).PropertyChanged += 
                      MainWindowViewModel_PropertyChanged;
        //Note I had to EnableInterception after
        //there was something listening to the 
        //INotifyPropertyChanged.PropertyChanged otherwise
        //the INPCMethodInvocation code would fail
        //to find a PropertyChangedEventHandler delegate
        //for the type being intercepted by the
        //INPCMethodInvocation code
        viewModel.EnableInterception();

    }

    private void MainWindowViewModel_PropertyChanged(object sender, 
                                     PropertyChangedEventArgs e)
    {
        MessageBox.Show(string.Format("{0} property changed " + 
                        "in MainWindowViewModel", e.PropertyName));
    }
}

And to prove it all works, here is a screenshot:

Image 17

Other Aspects

In this article, I have really just concentrated on performing one or two INPC based aspects, but I hope you can all see how you could roll your own aspects, such as a logging aspect where method calls are logged to a file, or a thread aspect where a call to the method would be marshaled to the UI thread, or even to throw an Exception if the current user's IWindowsPrincipal object does not allow them access to a certain method etc.

That's It

This article took quite a bit of time to research and a bit of trial and error, so if you liked this article and think it could be useful for you, or has maybe just given you some idea of how aspects could work for you, could you maybe leave a comment/vote?

Many thanks folks... Sacha.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2016
  • Codeproject MVP 2016
  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions

 
SuggestionAspect Injector Pin
pamidur11-Jul-15 10:25
pamidur11-Jul-15 10:25 
Take a look on free alternative for PostSharp
https://github.com/pamidur/aspect-injector[^]
QuestionHow to use INotifyPropertyChanged in EF Context.IDbSet(Of ABC) Pin
Reader Man San19-Jun-15 0:51
professionalReader Man San19-Jun-15 0:51 
AnswerRe: How to use INotifyPropertyChanged in EF Context.IDbSet(Of ABC) Pin
Sacha Barber19-Jun-15 1:24
Sacha Barber19-Jun-15 1:24 
GeneralRe: How to use INotifyPropertyChanged in EF Context.IDbSet(Of ABC) Pin
Reader Man San26-Jun-15 21:41
professionalReader Man San26-Jun-15 21:41 
QuestionYou're a machine Pin
Chris Maunder23-Jan-15 7:05
cofounderChris Maunder23-Jan-15 7:05 
AnswerRe: You're a machine Pin
Sacha Barber23-Jan-15 7:19
Sacha Barber23-Jan-15 7:19 
GeneralRe: You're a machine Pin
Chris Maunder23-Jan-15 7:50
cofounderChris Maunder23-Jan-15 7:50 
GeneralRe: You're a machine Pin
Sacha Barber23-Jan-15 9:05
Sacha Barber23-Jan-15 9:05 
AnswerRe: You're a machine Pin
Sacha Barber25-Jan-15 5:56
Sacha Barber25-Jan-15 5:56 
GeneralMy vote of 5 Pin
Mario Majčica4-Apr-13 4:19
professionalMario Majčica4-Apr-13 4:19 
QuestionCastle version doesn't update MainWindow when props are changed Pin
Wamiduku24-Mar-13 16:43
Wamiduku24-Mar-13 16:43 
GeneralMy vote of 5 Pin
Leo5615-Jun-11 22:52
Leo5615-Jun-11 22:52 
GeneralRe: My vote of 5 Pin
Sacha Barber23-Nov-11 21:51
Sacha Barber23-Nov-11 21:51 
QuestionProblems with Silverlight Pin
Ak_Dyl8-Feb-11 8:00
Ak_Dyl8-Feb-11 8:00 
AnswerRe: Problems with Silverlight Pin
Sacha Barber8-Feb-11 9:07
Sacha Barber8-Feb-11 9:07 
GeneralRe: Problems with Silverlight Pin
Ak_Dyl9-Feb-11 8:23
Ak_Dyl9-Feb-11 8:23 
GeneralRe: Problems with Silverlight Pin
Sacha Barber9-Feb-11 9:08
Sacha Barber9-Feb-11 9:08 
GeneralHere is my take on it Pin
Siderite13-Jan-11 23:49
Siderite13-Jan-11 23:49 
GeneralRe: Here is my take on it Pin
Sacha Barber14-Jan-11 0:01
Sacha Barber14-Jan-11 0:01 
GeneralRe: Here is my take on it Pin
Siderite14-Jan-11 0:15
Siderite14-Jan-11 0:15 
GeneralRe: Here is my take on it Pin
Sacha Barber14-Jan-11 0:19
Sacha Barber14-Jan-11 0:19 
GeneralRe: Here is my take on it Pin
Sacha Barber14-Jan-11 0:07
Sacha Barber14-Jan-11 0:07 
GeneralMy vote of 5 Pin
Mike Doyon9-Jan-11 3:59
Mike Doyon9-Jan-11 3:59 
GeneralRe: My vote of 5 Pin
Sacha Barber14-Jan-11 0:00
Sacha Barber14-Jan-11 0:00 
GeneralMy vote of 5 Pin
tonygeek8-Jan-11 8:22
tonygeek8-Jan-11 8:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.