Monday, July 27, 2009

Unity lifetime managers and WCF Integration

Although I have not written the final part of my BizTalk Fault Message support posts, I recently came across an issue that I thought needed to be shared.  I'm currently working on a medium-to-large project using NHibernate for data access.  One of the pillars of NHibernate development is session management.  Our data access is done across WCF services, using Unity for injecting the NHibernate sessions into our repositories.  Naively, our sessions were using the per-thread lifetime manager included with Unity.  This seemed to work great to select our data.  Unfortunately, when we began to update our data, a very strange issue would show up occasionally.

My developers began to tell me that every so often, a NonUniqueObjectException would be thrown when they tried to update a given entity.  The problem was that they could never reproduce it, nor were the steps the same every time.  I put this issue on the back burner so I could finish building out a service operation, when all of a sudden, I got the same error.

In my case, I was selecting a record with the first service call, and updating the same record with my second service call.  This simple set of service calls surfaced the issue, and it was reproducible about 80% of the time.  After spending a couple of minutes looking at the stack trace and generally debugging the issue, it finally dawned on me what was happening.  WCF's threading model, which was designed to make my services speedy, was actually hurting me in this case.

I don't know the exact details of how (for a good explanation of WCF IOCP threading internals, go here), but in a nutshell, the same thread that was obtained in my first service call was being used to service my second service call.  Because I was using the per-thread lifetime manager in Unity, the NHibernate session was not being cleaned out until the thread goes away.  Well, in WCF, the threads don't really go away.  Uh oh!

After conferring with Scott, we came up with the idea to build a Unity lifetime manager tied to WCF's OperationContext.  That way, our NHibernate session would live only for the life of the request, rather than the thread.

Starting with IExtension<OperationContext> and an implementation of IDispatchMessageInspector, I soon had an implementation of a UnityOperationContextLifetimeManager.  This is the one we ended up using to support our NHibernate sessions.  Once we used this lifetime manager instead of the per-thread lifetime manager, the NonUniqueObjectExceptions disappeared.

Once that was done, I figured since I did one of the extensible objects in WCF, I might as well do the rest.  The attached zip has lifetime managers to support all of the IExtensibleObject<T> implementations within WCF.

All of the lifetime managers are fairly straightforward, except for the UnityInstanceContextLifetimeManager.  This depends on the InstanceContext of a given service on which it is enabled.  PerSession is the default instancing mode for InstanceContext, but only when the transport supports sessions.  If the transport does not support sessions, the instancing mode is essentially PerCall.

Please note that the testing application is not necessarily a best practice for self-hosting a service, but I wanted you to see how to use the lifetime managers without having to worry about IIS (since IIS 6 doesn't have WAS and doesn't support the net.tcp binding).  Make sure if you are on Vista, you run this sample application as admin.

Download -