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
.
After debugging deep into NHibernate and LinFu I've found a workaround:
- Listen to the ILoadEventListener when lazy object is initialized by NHibernate
- 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:

