A NServiceBus Unit Of Work implementation for RavenDB

In my last post I introduced the new UoW support in NServiceBus 3.0. In this post I’ll show you how to use it to create a UoW implementation for RavenDB. Ayende has already blogged about one way to do it but now there is a better way.

Sharing the session

The first thing we need to take care of is sharing the session between our message handler(s) and the actual unit of work implementation. We could do this using thread static but that has some issues that I have mentioned before.

Instead we will use the new support for child containers  in NServiceBus 3.0. This means that all dependencies configured as single call effectively becomes static within the context of one transport message and this is exactly what we need.

To resolve a Raven document session from the container we’ll add the following configuration (I’m using StructureMap but any one of the other containers except Spring and Unity would work)

The above code tells the container to create a new IDocumentSession using the lambda specified and the fact that all message processing is done using a child container means that all message handlers processing the message will get the same session instance.

Implementing the Unit Of Work

In RavenDB you need to explicitly call IDocumentSession.SaveChanges() in order to persist your data to the database. So to avoid making this call in all our handlers we add a unit of work implementation that takes care of it.  This saves typing and makes sure that our developers won’t introduce bugs by forgetting to make the call.

Note that we’re taking a dependency on the IDocumentSession and given that the UoW is resolved from the same child container as the handlers we’ll get the same session instance. Raven doesn’t need any special setup so the only thing we need do is call SaveChanges if End() is called and no exception occurred.

The final thing we have to do is make NServiceBus use our UoW. We do this by configuring it in the container so that NServiceBus will find it and use it:

 

What about disposing the session?’

Again we’re rescued by the child containers and the fact that all single call components that where created in the child container is getting disposed by the main container when the child container is disposed. NServiceBus is disposing the child container when the processing of a transport message is complete and this has the effect that any object implementing IDisposable will be disposed. Luckily for us IDocumentSession does just this!

 

With this in place we can create very clean message handlers  that interact with Raven:


 

Working code please…

A working sample can be found over at my github account.

  • I’m using the excellent NuGetPowerTools so the solution will automatically download the required dependencies.
  • Make sure to start the sample as Administrator in order to let NServiceBus create the queues for you!
  • The sample assumes that you have a RavenDB at http://localhost:8080

Any feedback is much appreciated!

This entry was posted in NServiceBus, RavenDB. Bookmark the permalink. Both comments and trackbacks are currently closed.
  • Pingback: Unit of work in NServiceBus 3.0

  • Erik Lindström

    Looks great. Improves alot instead of using a MessageModule. Would be possible for you to do an Error method instead of supplying the exception as and argument to method End? 
    Then you could get rid of the evil if case in End method :-)
    Maybe you could add the failed message in that Error method as well?

    • Anonymous

      We discussed that on our internal dev group but decided to stick with the current “terse”  version of the interface. 

  • Matt Johnson

    Thanks for the article.  I use AutoFac instead of StructureMap, and most of it is similar, but I ran into one problem that took awhile of pulling my hair out.  the session should be registered as InstancePerLifetimeScope.  Otherwise, you get a different session in your event handler than the one that the RavenUnitOfWork gets, and then SaveChanges is never called.  Here is the registration with autofac: https://gist.github.com/2127176