Gennadiy Donchyts Just another WordPress weblog

31Jul/090

Making NHibernate lazy-loading PostSharp-ed objects work.

I'm using PostSharp to add implementation of INotifyPropertyChanged in AOP way using PostSharp compound aspect.

At the same time object has to be saved into a database and loaded in a lazy way (NHibernate + LinFu as a DynamicProxy). It seems that when object is loaded - all aspects disappear in a proxy object created by a DynamicProxy. All required fields are present in the proxy type but aspects are not initialized and PostSharp  instanceCredentials = {0}.

Gael Fraiteur sent me a message after I Twittered about the problem (so, Twitter works! :) ):

@gena_d Look at http://tiny.cc/zIXFT. Call this method: LaosUtils.InitializeCurrentAspects() if the aspect constructor is skipped.

Thanks! But unfortunatelly it was not a solution for me since object even has no aspect implementation injected into it, it happens in the constructor which is skipped :( .

QuickWatch_LazyAOPObject

After debugging deep into NHibernate and LinFu I've found a workaround:

  1. Listen to the ILoadEventListener when lazy object is initialized by NHibernate
  2. During load, inject another instance of NotifyPropertyChangedImplementation into proxy and forward event from underlying object to that implementation.
public void OnLoad(LoadEvent @event, LoadType loadType)
{
    defaultLoadEventListener.OnLoad(@event, loadType);

    InitializePropertyChangedAspect(@event.Result);
}

///
/// Connects property changed events of the proxy object to the real object
/// so when PropertyChanged event is fired - it will be redirected to the proxy.
///
///

private void InitializePropertyChangedAspect(object o)
{
    if (!(o is INHibernateProxy) || !(o is IComposed))
    {
        return;
    }

    var proxyObject = (INHibernateProxy) o;
    var lazyInitializer = proxyObject.HibernateLazyInitializer;
    var realObject = lazyInitializer.GetImplementation();

    // initialized property changed aspect implementation
    // and redirects events fired in the wrapped object
    // to the aspect implementation in the parent object (proxy)
    var aspect = new NotifyPropertyChangedImplementation(o, InstanceCredentials.Null, false);
    ((IComposed) o).SetImplementation(InstanceCredentials.Null, aspect);

    var notifiable = (INotifyPropertyChanged) realObject;
    notifiable.PropertyChanged += ((sender, e) => aspect.OnPropertyChanged(proxyObject, e));
}

As a result a client code subscribing to a proxy object can listen to a PropertyChanged event. The code looks a bit ugly, it would nicer if DynamicProxy can handle these events.

After implementation of aspect is injected - the proxy object looks like this:

Comments (0) Trackbacks (0)

No comments yet.


Leave a comment


No trackbacks yet.