>

In this post I will demonstrate a way to automatically manage a UnitOfWork (UoW) for Windows Communication Foundation (WCF) service requests. This is the equivalent of “Session per request” that is popular for Web applications. The reason for all this is to move transaction management out of user code resulting in cleaner and more maintainable applications.

The semantics of my UoW is the following, for each request to my WCF service:

    1. Create a new UoW and initialize it
    2. Cache the UoW in StructureMap for the duration of the request
    3. Commit and dispose the UoW when the request finishes
    4. Rollback the UoW if the service throws an exception

My interface for the UoW looks like this:

   1:  public interface IUnitOfWork : IDisposable
   2:  {
   3:      void Initialize();
   4:      void Commit();
   5:      void Rollback();
   6:  }

 

To do all this we need the following infrastructure.

    1. Basic StructureMap integration for WCF
    2. A way to cache objects for the duration of the service call
    3. Integration between the cache StructureMap
    4. Some hooks in WCF to allow us the Initialize and commit the UoW
    5. Another hook to detect exceptions and rollback the UoW

Let’s taka a closer look at how we can’t implement all this.

Basic StructureMap integration for WCF

This is a solved problem so I wont go into the details (Jimmy Bogard has an excellent post on the subject). Basically this means creating a “ServiceHostFactory” which in the end allows us to specify our own “instance provider”. Using this provider we can use StructureMap to instantiate the reuested instances.

Building a WCF per request cache

To enable caching I decided to cache objects in the WCF InstanceContext. The instance context is isolated for each service instance. This means that we must make sure that WCF creates a new Instance for each call (the default is one Instance per session). This is easily done by adding the following to our service implementations:

   1:  [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]

Ok, but how do we cache stuff in the InstanceContext? Unfortunately WCF doesn't provide any collection like HttpRequest.Current.Items so we have to use the extensibility hooks in WCF to solve the problem. In this case we add our own Instance extension that can handle the caching for us. This is done by creating  a class that implements IExtension<InstanceContext>. The implementation looks like this:

   1:  public class WCFContextCacheExtension : IExtension<InstanceContext>
   2:  {
   3:      private MainObjectCache cache;
   4:   
   5:      public IObjectCache Cache
   6:      {
   7:          get { return cache; }
   8:      }
   9:   
  10:      public static WCFContextCacheExtension Current
  11:      {
  12:   
  13:          get
  14:          {
  15:              return OperationContext.Current.
  16:                  InstanceContext.Extensions.Find<WCFContextCacheExtension>();
  17:          }
  18:   
  19:      }
  20:      public void Attach(InstanceContext owner)
  21:      {
  22:          cache = new MainObjectCache();
  23:      }
  24:   
  25:      public void Detach(InstanceContext owner)
  26:      {
  27:   
  28:      }
  29:  }

Note that I’m using the MainObjectCache from StructureMap as the store for my cached objects, the reason for this will be explained when we take a look at how this can be integrated with StructureMap. I’ve also added a convenience method that finds the extension from the InstanceContext. But how do we make sure that our extension is added to every new Instance?

My approach is to implement a “InstanceContextInitializer” which is added to the dispatch runtime. This is accomplished with this modification to my StructureMap WCF integration:

   1:  ed.DispatchRuntime
   2:     .InstanceContextInitializers
   3:        .Add(new InstanceContextCacheInitializer()); 

The implementation of the InstaceContextInitializer is trivial:

   1:  public class InstanceContextCacheInitializer : IInstanceContextInitializer
   2:  {
   3:      public void Initialize(InstanceContext instanceContext, Message message)
   4:      {
   5:          instanceContext.Extensions.Add(new WCFContextCacheExtension());
   6:      } 
   7:  }

Ok, now that we have a way to cache objects in the InstanceContext lets see how we can integrate this with the StructureMap way of caching instances .

A WCFInstanceContextCache for StructureMap

Extending StructureMap with a custom caching solution is done by implementing your own “lifecycle”. (Here is an indepth discussion of scoping in StructureMap.)

In this case our custom lifecycle would look like this:

   1:  public class WCFInstanceContextLifecycle : ILifecycle
   2:  {
   3:      public void EjectAll()
   4:      {
   5:          FindCache().DisposeAndClear();
   6:      }
   7:   
   8:      public IObjectCache FindCache()
   9:      {
  10:          return  WCFContextCacheExtension.Current.Cache;
  11:      }
  12:  }

As you can see StructureMap requires our cache to implement the IObjectCache interface hence the use of MainObjectCache above. Noting magic here we just fetch the cache from our InstanceContext extension and let StructureMap do the rest.

The will enable us to configure StructureMap like this in order to cache objects for the duration of a service call:

   1:  x.ForRequestedType<IUnitOfWork>()
   2:       .LifecycleIs(new WCFInstanceContextLifecycle())
   3:       .AddConcreteType<TestUnitOfWork>();

Now that we have a way to cache our UoW for the duration of each service call we can move on to making sure that the UoW is initialized and committed automatically for each request.

How to manage the UoW on a Per request basis

To enable us to automatically initialize and commit our UoW we need a way to hook up to the WCF call pipeline. This is done by adding a custom IDispatchMessageInspector (a deeper explanation of MessageInspectors is found here).

To enable us to add message inspectors easily I've added the following feature to my StructureMap WCF integration:

   1:  foreach (var messageInspector in container.GetAllInstances<IDispatchMessageInspector>())
   2:  {
   3:      ed.DispatchRuntime.MessageInspectors.Add(messageInspector);
   4:  }

This gives me an easy way to add MessageInspectors just by configuring them in StructureMap.

   1:  x.ForRequestedType<IDispatchMessageInspector>()
   2:      .AddConcreteType<UnitOfWorkMessageInspector>();

 

With this in place it’s easy to implement my own “UnitOfWorkMessageInspector” that hooks up to WCF and performs the work. This looks like this:

   1:  public class UnitOfWorkMessageInspector: IDispatchMessageInspector
   2:  {
   3:      private readonly IContainer container;
   4:   
   5:      public UnitOfWorkMessageInspector(IContainer container)
   6:      {
   7:          this.container = container;
   8:      }
   9:   
  10:      public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
  11:      {
  12:          var unitOfWork = container.GetInstance<IUnitOfWork>();
  13:   
  14:          Debug.WriteLine("Before invoke");
  15:          unitOfWork.Initialize();
  16:   
  17:          return null;
  18:      }
  19:   
  20:      public void BeforeSendReply(ref Message reply, object correlationState)
  21:      {
  22:          var unitOfWork = container.GetInstance<IUnitOfWork>();
  23:   
  24:          Debug.WriteLine("After invoke");
  25:          unitOfWork.Commit();
  26:          unitOfWork.Dispose();
  27:      }
  28:  }

As you can see we Initialize, Commit and Dispose the UoW for each “Message” going in and out of our service.

Notes:

  • BeforeSend reply will still be invoked even if the operation is “OneWay”.
  • As you can see we always commits, this works because the implementations of IUnitOfWork is required to always start a new transaction after commit and rollback. This is to allow user code to perform manual commits and rollback. This feature is also required to enable other errorhandlers to update application state if needed. (more on this below)

Ok, so far so good. Lets look at the final piece of the puzzle. The rollback…

Rollback the UoW if the service call throws an exception

By now you’ll probably guess how this will be done:) WCF is extensible beyond belief. First we add some more code that allows us to autoregister WCF Errorhandlers through StructureMap.

   1:  foreach (var errorHandler in container.GetAllInstances<IErrorHandler>())
   2:  {
   3:      cd.ErrorHandlers.Add(errorHandler);
   4:  }

With this in place we can configure a custom “UnitOfWorkErrorHandler” that can perform the rollback in case of an exception. The fact that we are resolving the errorhandlers using StructureMap means that we can have the container itself injected into them if necessary.

   1:  public class UnitOfWorkErrorHandler : IErrorHandler
   2:  {
   3:      private readonly IContainer container;
   4:   
   5:   
   6:      public UnitOfWorkErrorHandler(IContainer container)
   7:      {
   8:          this.container = container;
   9:      }
  10:   
  11:      public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
  12:      {
  13:          var uow = container.GetInstance<IUnitOfWork>();
  14:   
  15:          Debug.WriteLine("Rolling back UoW");
  16:   
  17:          uow.Rollback();
  18:      }
  19:   
  20:      public bool HandleError(Exception error)
  21:      {
  22:          return false;
  23:      }
  24:  }

But why are you not injecting the IUnitOfWork directly?

The reason for this is that there is no ongoing call when the error handler is instantiated so the cache wouldn't work (We are storing the cache in the active service instance remember). The workaround would be to add some kind of “lazy dependency” feature to StructureMap that would instantiate our UoW the first time it’s accessed. But until then will just use the container directly.

The fact that a new transaction is started after rollback enables the other errorhandlers to perform custom business logic that requires an active transaction eg. logging to a database, publishing events to an service bus etc. ( remember that the  “new UoW transaction” is going to be committed by the message inspector above)

Summary

Phew, we are finally done. WCF and StructureMap is really easy to extend. There is a lot of extensions required for this to work but I like the fact that each extensions does its thing and thereby adhering to Single Responsibility Principle. Having the infrastructure managing your UoW is a great way to keep your code clean and minimizes the risk of “forgetting” transaction management.

Resources

The code for the StructureMap WCF Integration can be found here.

A test that shows the configuration and usage of the UoW is here

And the code for the WCF UoW is here

Jimmy Bogard has written a post about this (but it turned out to have some threading problems but It got me stared down the right path)

Donald Belcham at igloocoder.com has posted some info on the subject

AltOxite has a great UoW implementation for Fluent NHibernate that I have shamelessly copied :)

As always comment, suggestions etc is most welcome!