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...
- 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!