INotifyPropertyChanged as AOP

The purpose of this post is to demonstrate several ways to use INotifyPropertyChanged as an AOP aspect in your business entities. I will use DynamicProxy for AOP and NHibernate as orm mapper. Althought all methods can be plugged into nhibernate using tuplizer, I will skip this part until the final solution.

The Problem

Let’s say you have to implement INotifyPropertyChanged for several entities of your domain. This is an example of implementation:
public class Customer : INotifyPropertyChanged
   {
       public event PropertyChangedEventHandler PropertyChanged;

       protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
       {
           PropertyChangedEventHandler changed = PropertyChanged;
           if (changed != null) changed(this, e);
       }

       private string _name;
       public string Name
       {
           get { return _name; }
           set
           {
               _name = value;
               OnPropertyChanged(new PropertyChangedEventArgs("Name"));
           }
       }

       private string _address;
       public string Address
       {
           get { return _address; }
           set
           {
               _address = value;
               OnPropertyChanged(new PropertyChangedEventArgs("Address"));
           }
       }
   }

First way: proxy with concrete target

I will start with proxies right now. If you want to know more about dynamic proxy I suggest this link.
The big picture

first

The client api call “set_Name” on the proxy, the proxy forwards this call to the interceptor stack. The PropertyInterceptor “proceed and wait” this invocation to the concrete type. The operaton is completed in the concrete type and then the interceptor raise the PropertyChanged event to the client.
The domain entity is defined as follows:

public class Customer : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public string Name { get; set; }
    public string Address { get; set; }
}

Note: the event is never raised inside the concrete class.
My proxy could by generated this way:

var proxyGenerator = new ProxyGenerator();
proxyGenerator.CreateInterfaceProxyWithTarget(typeof (Customer), 
                                                            new Customer(), 
                                                            new PropertyInterceptor());

The class PropertyInterceptor is trivial so I wont talk about it for now.
It’s an horrible workaround and don’t worth it. Why? because you end up with some kind of partial class that doesn’t work as expected if you don’t hang the interceptor.
Let’s clarify it, if you see “Customer : INotifyPropertyChanged” and it has a suitable constructor, you can assume that this class will work well even without proxy, interceptor or any kind of initialization.

Second way: proxy with concrete target (not INotifyPropertyChanged)

Maybe you are thinking right now: why do not remove INotifyPropertyChanged and put this interface into the proxy. Because the proxy is automatically generated your client api will need to do something like this:

Customer customer; //= Get the customer from somewhere;
            var notificable = customer as INotifyPropertyChanged;
            if(notificable != null)
                notificable.PropertyChanged += //...

And again, this is an horrible workaround. What happens if notificable is null? somebody has removed the additional interface from the proxy.

Third way: enough is enough

GoF: Program to an interface, not an implementation. I like very much this interview.
Then… your interface could be implemented in many ways (¿or not implemented at all?).
I will start showing this interface:

public interface ICustomer : INotifyPropertyChanged
{
    string Name { get; set; }
    string Address { get; set; }
}

I can guarantee that if you hold an ICustomer instance somewhere, it will work as you expect.
Do I need to code twice, one for the interface and one for the concrete class? NO. If this were the case I would not be bothered to write this beautiful post.
You don’t need to code twice because you don’t need any concrete implementation of ICustomer. I know, you are more confused now.
Fabio Maulo wrote a great post. My first impression when I read it was “Fabio is insane”, the second impression was “Fabio is really insane”. Here I’m, with a good reason to let my entities to be “services” in terms of IoC.
The big picture:

third

The client api invokes set_Name and the proxy pass this call over the interceptor stack. The PropertyChangedInterceptor still behave as the first example. The second interceptor “DataStore” store the data in a Dictionary and doesn’t proceed with the invocation because there isn’t any target!
Despite the fact that there is not a real implementation of ICustomer, there is an implementation that dynamic proxy has generated for me. The profit of using this approach is that you really need just one interceptor or two for the whole domain. Let me guess: not all of your entities are POCO. Nor mine, so the point is that you can go with “abstract” (search the interview about this) and if you really really need a concrete implementation write it, but write his interface first.

My implementation

Last but not least, I let the container to generate the proxies when a consumer of ICustomer interface needs it. I managed to create an extension for the registration api in Windsor:

container.Register(Component.For<ICustomer>()
                            .NotifyOnPropertyChange()
                            .TargetIsCommonDatastore());

There are two different things, you could service with a concrete type and still use “NotifyOnPropertyChange”. If you use NotifyOnPropertyChange, the service must implement INotifyPropertyChanged.
For instance the consumer of the ICustomer could be an API that wants to create a new Customer in our system, or NHiberante. In NHibernate I just have to map the interface to the database.
On the other hand, NHibernate need to know how to create an instance of an ICustomer, “Tuplizer” and “IInstantiator” is the solution (as Fabio has mentioned in his blog).

/// <summary>
/// Resolve an entity through ServiceLocator.
/// This allow to inject a proxy and intercepted entity.
/// </summary>
public class ServiceLocatorInstantiator : IInstantiator
{
    #region IInstantiator Members

    private readonly Type _entityType;

    public ServiceLocatorInstantiator(Type entityType)
    {
        _entityType = entityType;
    }

    public object Instantiate(object id)
    {
        var obj = ServiceLocator.Current.GetInstance(_entityType);
        return obj;
    }

    public object Instantiate()
    {
        return Instantiate(null);
    }

    public bool IsInstance(object obj)
    {
        return _entityType.IsInstanceOfType(obj);
    }

    #endregion
}

Fabio’s instantiator and mine have the same aim. The main difference is that my IInstantiator uses a ServiceLocator while the other uses DynamicProxy directly.
The sample project is in unhaddins.
I hope you enjoy this history as I did.

kick it on DotNetKicks.com

blog comments powered by Disqus
  • Categories

  • Archives