NHibernate and the Unit of Work pattern (Part 3)

Introduction

In the previous two posts which you can find here and here I introduced the Unit of Work pattern and developed a working version based on NHibernate. One weak point of the shown implementation is that it is strictly non thread safe. In NHibernate the session object takes the role of the Unit of Work container. The session object is not thread safe! That is a session instance may not be accessed from different threads. If your application is running on multiple threads (typically an application running on the server) then you have to open a new session instance for each running thread.

In this post I want to improve the implementation of the Unit of Work pattern such as that it is thread safe. The class which starts a new unit of work is a static class. All static members of this class are accessible from each thread of the application domain in which your application is running. Now fortunately .NET provides us a mean to define pseudo static fields in a type which are local to a single thread. That is this state is not shared between different threads. Each thread has its own thread static state. To make a field thread static one has to decorate it with the [ThreadStatic] attribute.

The easiest and most pragmatic approach would now be to just decorate our _innerUnitOfWork field of the UnitOfWork class with the [ThreadStatic] attribute. But eventually we want to keep additional state in our Unit of Work. Thus we implement a special Data class which is a kind of a wrapper around a Hashtable.

Container for Thread Static State

There are 2 possible scenarios I want to discuss. You either develop an application with a web client or an application with a windows client (e.g. WinForms).

In a web application one has the so called Http context for each request. Multiple requests from different clients can run at the same but each of them runs on a different thread and has it's own context. In this situation we store the data relevant to the unit of work in the context of the request.

In a windows client application (i.e. Smart Client Application) on the other hand we have a single client that might run on different threads at the same time. In this situation we "attach" the data relevant to the unit of work in so called thread-static fields. A thread-static field is not shared between different threads in the same application. To make a (static) field thread-static we have to just decorate it with a [ThreadStatic] attribute.

In our Unit of Work implementation we have the static UnitOfWork class which contains a static field _innerUnitOfWork of type IUnitOfWork. We now need to change this since this kind of implementation is not thread safe. Since we might want to save other data in a thread safe way as well (not just the current instance of the unit of work) we choose a slightly more sophisticated solution.

Let's define a static class Local which encapsulates the details whether we run a web- or a win-application. This class has just one (static) read-only property Data of type ILocalData.

using System;
using System.Collections;
 
namespace NHibernateUnitOfWork
{
    public static class Local
    {
        static readonly ILocalData _data = new LocalData();
 
        public static ILocalData Data
        {
            get { return _data; }
        }
 
        private class LocalData : ILocalData
        {
            // implementation details to de defined
        }
    }
}

All details of our implementation are now "hidden" in the class LocalData which we choose to be a private child class of the Local class. We now want to be able to save into and read data from this local container via a key, e.g.

Local.Data["some key"] = someValue;
// or
otherValue = Local.Data["other key"];

This should be in a thread safe way. Obviously the above sample client code implies that we use some kind of dictionary to internally store our data.

As usual we formulate our intention in a unit test which might look like this

using System;
using NUnit.Framework;
 
namespace NHibernateUnitOfWork.Tests
{
    [TestFixture]
    public class LocalData_Fixture
    {
        [Test]
        public void Can_store_values_in_local_data()
        {
            Local.Data["one"] = "This is a string";
            Local.Data["two"] = 99.9m;
            var person = new Person {Name = "John Doe", Birthdate = new DateTime(1991, 1, 15)};
            Local.Data[1] = person;
 
            Assert.AreEqual(3, Local.Data.Count);
            Assert.AreEqual("This is a string", Local.Data["one"]);
            Assert.AreEqual(99.9m, Local.Data["two"]);
            Assert.AreSame(person, Local.Data[1]);
        }
    }
}

The test shows that I want to be able to not only store basic types but any complex type in my local data container. In this case a string, an integer and an instance of a Person class. The Person class is very basic at looks like follows

public class Person
{
    public virtual Guid Id { get; set; }
    public virtual string Name { get; set; }
    public virtual DateTime Birthdate { get; set; }
}

Please also note that I use keys of different type (string and int).

Implementation for Smart Client Applications

Let's first assume that we want to provide a thread safe unit of work implementation for the smart client application. Then the most basic implementation to fulfill  this test is

private class LocalData : ILocalData
{
    private static Hashtable _localData = new Hashtable();
 
    public object this[object key]
    {
        get { return _localData[key]; }
        set { _localData[key] = value; }
    }
 
    public int Count
    {
        get { return _localData.Count; }
    }
}

I just take a hash table as local storage and define an indexer property and a Count property (Note: a HashTable is an often used implementation of a Dictionary).

We want to also be able to clear the content of the local store and thus we define the following test

[Test]
public void Can_clear_local_data()
{
    Local.Data["one"] = "This is a string";
    Local.Data["two"] = 99.9m;
    Assert.AreEqual(2, Local.Data.Count);
    Local.Data.Clear();
    Assert.AreEqual(0, Local.Data.Count);
}

The code to fulfill this test is trivial, just add the code snippet below to the LocalData class

public void Clear()
{
    _localData.Clear();
}

Unfortunately the test still faults when run! This is because the local data storage is static and all test methods access the same container we have a "side effect" which we must now compensate. We can do it by just clearing the local data container before each test. Add this code to the test fixture class to compensate the side effect

[SetUp]
public void SetupContext()
{
    Local.Data.Clear();     // start side-effect free!
}

Re-run all tests. They should now all pass...

And now comes the "tricky" part of the implementation where we want to guarantee that our local data store is indeed thread safe. Let's first define a test for this scenario

private ManualResetEvent _event;
 
[Test]
public void Local_data_is_thread_local()
{
    Console.WriteLine("Starting in main thread {0}", Thread.CurrentThread.ManagedThreadId);
    Local.Data["one"] = "This is a string";
    Assert.AreEqual(1, Local.Data.Count);
 
    _event = new ManualResetEvent(false);
    var backgroundThread = new Thread(RunInOtherThread);
    backgroundThread.Start();
 
    // give the background thread some time to do its job
    Thread.Sleep(100);
    // we still have only one entry (in this thread)
    Assert.AreEqual(1, Local.Data.Count);
 
    Console.WriteLine("Signaling background thread from main thread {0}", Thread.CurrentThread.ManagedThreadId);
    _event.Set();
    backgroundThread.Join();
}
 
private void RunInOtherThread()
{
    Console.WriteLine("Starting (background-) thread {0}", Thread.CurrentThread.ManagedThreadId);
    // initially the local data must be empty for this NEW thread!
    Assert.AreEqual(0, Local.Data.Count);
    Local.Data["one"] = "This is another string";
    Assert.AreEqual(1, Local.Data.Count);
 
    Console.WriteLine("Waiting on (background-) thread {0}", Thread.CurrentThread.ManagedThreadId);
    _event.WaitOne();
    Console.WriteLine("Ending (background-) thread {0}", Thread.CurrentThread.ManagedThreadId);
}

In the above code I run two threads in parallel, the thread on which the test is running (let's call it the main thread) and an additional background thread. The code which is executed in the background thread is implemented in the helper method RunInOtherThread. To be able to synchronize the two threads I use an Event, in this case a ManualResetEvent. I have put some Console.WriteLine statements in the code for debugging purposes.

In the main thread I add some data to the local data store. Then I spin up the background thread. In the background thread I first test that my (thread-) local data store is empty and then also fill in some data. With the Assert statements I test that we really have a thread safe behavior.

The only change needed to make my implementation thread safe is to decorate the static field _localData with the [ThreadStatic] attribute.

[ThreadStatic]
private static Hashtable _localData = new Hashtable();

When the test is run it should pass and produce an output similar to this

image

Implementation for Web

As mentioned above in this scenario we want to store our local data in the context of the current HTTP request.

First I want to provide an indicator whether I am running in web and thus I add the following to the code snippet to the LocalData class

public static bool RunningInWeb
{
    get { return HttpContext.Current != null; }
}

Here I use the HttpContext class of the .NET framework (namespace System.Web). It's static property Current is equal to null if we do not run in the context of a web application.

To abstract the details of the context (web- or smart client application) I define a private read-only property LocalHashtable as below

private static readonly object LocalDataHashtableKey = new object();
 
private static Hashtable LocalHashtable
{
    get 
    {
        if (!RunningInWeb)
        {
            if (_localData == null)
                _localData = new Hashtable();
            return _localData;
        }
        else
        {
            var web_hashtable = HttpContext.Current.Items[LocalDataHashtableKey] as Hashtable;
            if (web_hashtable == null)
            {
                web_hashtable = new Hashtable();
                HttpContext.Current.Items[LocalDataHashtableKey] = web_hashtable;
            }
            return web_hashtable;
        }
    }
}

In this code I use the RunningInWeb helper method to distinguish the two cases. In the case of NOT running in web context I test whether my thread static _localData field is equal to null, and If so I initialize it with a new instance of type Hashtable. I then return this instance. On the other hand, when running in web context I try to access a hash table instance in the Items collection of the current Http context. If I do not find such an instance then I create a new one and put it into the items collection of the current context. I then return the instance.

Now I have to locate every place in the LocalData class where I access the _localData field directly and replace it with a reference to the LocalHashtable property. E.g. the indexer will have to be changed as follows

public object this[object key]
{
    get { return LocalHashtable[key]; }
    set { LocalHashtable[key] = value; }
}

Our thread- and/or Http context local data store is now complete and we can use it in our UnitOfWork class.

Make Unit Of Work implementation thread safe

To make our unit of work implementation thread safe we change the implementation of our static UnitOfWork class as shown below

public static class UnitOfWork
{
    private static readonly IUnitOfWorkFactory _unitOfWorkFactory = new UnitOfWorkFactory();
 
    public static Configuration Configuration
    {
        get { return _unitOfWorkFactory.Configuration; }
    }
 
    public const string CurrentUnitOfWorkKey = "CurrentUnitOfWork.Key";
 
    private static IUnitOfWork CurrentUnitOfWork
    {
        get { return Local.Data[CurrentUnitOfWorkKey] as IUnitOfWork; }
        set { Local.Data[CurrentUnitOfWorkKey] = value; }
    }
 
    public static IUnitOfWork Current
    {
        get
        {
            var unitOfWork = CurrentUnitOfWork;
            if (unitOfWork == null)
                throw new InvalidOperationException("You are not in a unit of work");
            return unitOfWork;
        }
    }
 
    public static bool IsStarted
    {
        get { return CurrentUnitOfWork != null; }
    }
 
    public static ISession CurrentSession
    {
        get { return _unitOfWorkFactory.CurrentSession; }
        internal set { _unitOfWorkFactory.CurrentSession = value; }
    }
 
    public static IUnitOfWork Start()
    {
        if (CurrentUnitOfWork != null)
            throw new InvalidOperationException("You cannot start more than one unit of work at the same time.");
        
        var unitOfWork = _unitOfWorkFactory.Create();
        CurrentUnitOfWork = unitOfWork;
        return unitOfWork;
    }
 
    public static void DisposeUnitOfWork(IUnitOfWorkImplementor unitOfWork)
    {
        CurrentUnitOfWork = null;
    }
}

As you can see the field _innerUnitOfWork has gone and is replaced by a private property CurrentUnitOfWork. This property in turn uses the previously defined Local class to store the current unit of work item.

Note that there is one place in our unit tests that makes a reference to the field _innerUnitOfWork and must thus be changed. It's the method ResetUnitOfWork in the class UnitOfWork_With_Factory_Fixture. The new implementation is

private void ResetUnitOfWork()
{
    // assert that the UnitOfWork is reset
    var propertyInfo = typeof(UnitOfWork).GetProperty("CurrentUnitOfWork",
                        BindingFlags.Static | BindingFlags.SetProperty | BindingFlags.NonPublic);
    propertyInfo.SetValue(null, null, null);
}

When run, all tests should again pass. So now our implementation of the unit of work is thread safe.

You can find the full code here.

Enjoy

Blog Signature Gabriel .

Print | posted on Saturday, April 26, 2008 7:04 AM

Comments on this post

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
I can't access the code using tortoisesvn, weird.

Error: REPORT request failed on '/svn/!svn/vcc/default'

Error: REPORT of '/svn/!svn/vcc/default': 400 Bad Request (http://hibernatingrhinos.googlecode.com)

Any help?
Left by Chua Wen Ching on Apr 26, 2008 8:32 PM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
Create a new folder. Right click and choose "SVN chekcout...". Enter the URL http://hibernatingrhinos.googlecode.com/svn/trunk/UnitOfWork/" and press ok
with me it works (I just tried it to be shure)
Left by Gabriel Schenker on Apr 27, 2008 7:10 AM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
Ya I tried that yesterday and 1 minute ago ... it didn't work ...

Am I the only one facing this problem? Weird ...
Left by Chua Wen Ching on Apr 27, 2008 2:09 PM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
@Chua: what SVN client do you have? I use TortoiseSVN. I never had problems so far with it.
Left by Gabriel Schenker on Apr 28, 2008 9:56 AM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
I don't think the Configuration creation is thread safe. The following test fails every time (the configuration seems to get in a right state and fails in different ways):


private Configuration _configuration1;
private Configuration _configuration2;

[Test]
public void Configuration_creation_is_thread_safe()
{
Console.WriteLine("Getting configuration in main thread {0}", Thread.CurrentThread.ManagedThreadId);
var backgroundThread = new Thread(RunInOtherThread);
backgroundThread.Start();
_configuration1 = _factory.Configuration;
Console.WriteLine("Got configuration in main thread {0}", Thread.CurrentThread.ManagedThreadId);
backgroundThread.Join();
Console.WriteLine("Configuration 1 hashcode {0}, configuration 2 hashcode {1}", _configuration1.GetHashCode(), _configuration2.GetHashCode());
Assert.IsTrue(object.ReferenceEquals(_configuration1, _configuration2));
}



private void RunInOtherThread()
{
Console.WriteLine("Getting configuration in background thread {0}", Thread.CurrentThread.ManagedThreadId);
_configuration2 = _factory.Configuration;
Console.WriteLine("Got configuration in background thread {0}", Thread.CurrentThread.ManagedThreadId);
}


Adding some double checked locking around the initialisation makes it thread safe:


public Configuration Configuration
{
get
{
if (_configuration == null)
{
lock (_initLock)
{
InitConfiguration();
}
}
return _configuration;
}
}

private void InitConfiguration()
{
if (_configuration == null)
{
_configuration = new Configuration();
... etc ...

}
}
}

Left by Dan on May 21, 2008 7:59 AM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
My code looks nice doesn't it. I forgot to add that I moved creation of the SessionFactory into the InitConfiguration method.
Left by Dan on May 21, 2008 8:04 AM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
I've read elsewhere that you CANNOT use ThreadStatic with NHibernate and ASP.NET. Why do you use it here then? I'm having issues with ASP.NET production application that there ends up being multiple NHibernate sessions retrieving data so the users get weird errors.
Left by James Vander Zanden on Jan 10, 2009 2:57 AM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
@James: in ASP.NET the UoW is NOT thread static! Have a look at the implementation of the LocalData class where the scenario is handled
Left by Gabriel N. Schenker on Jan 12, 2009 8:39 PM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
So we call UnitOfWork.Start(). Then use UnitOfWork.CurrentSession, but the factory is not on the ASP.NET session? Or is it? Would it be better to create a IUnitOfWork.Session and use that? That seems to work... Thanks for your help!
Left by James Vander Zanden on Jan 15, 2009 5:48 AM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
@James: The UoW Factory is created once (and only once) when the application (Web or Win) is started and the UoW class is first accessed. The factory is then available during the lifetime of the application.
Left by Gabriel N. Schenker on Jan 21, 2009 1:34 AM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
Great articles! I am a little puzzled about how you would go about using this in ASP.NET. If you create an IHttpModule with the single job of creating the configuration, then the web-project has to have a reference to NHibernate... right? As far as I can see the only way to configure the UoW is by calling UnitOfWork.Configuration which returns NHibernate.Cfg.Configuration.
Left by Rune on Feb 17, 2009 5:15 AM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
The NHibernate Session already is a UnitOfWork so I wonder if you need a special pattern to abstract from the session. In most cases it’s likely that you only work with NHibernate as you ORM. If you don’t have the need to support other ORMs than further abstraction is just an intellectual exercise.
Secondly, the session as the UnitOfWork should be kept as short as possible otherwise the identity map will keep on growing and you will get concurrent modification exceptions especially in smart client applications. So, I doubt that it is generally a good idea to keep the session static (either application or thread static) unless you design you application accordingly.
As for web applications, I do believe that each request gets its own thread and the web application container makes sure that two concurrent requests are not handled by the same thread at the same time (this it at least how it’s implemented in J2EE world). Having that in mind, it should be possible to bind the session to the thread when the container starts to handle the request and store it in the session when the request has been handled. I guess that’s mainly what the HTTPContext does as well. But, if you use it in such way, you need to design your application to flush and close the session from time to time and to bind the UnitOfWork (or the NhibernateSession) to the Web session only if you need it across requests.
Left by Carsten on May 25, 2009 4:37 AM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
I'm having a problem with your code and a multithreaded application. The UI thread dispatches a background thread which syncs some message lists with the database. It all runs fine until the UI thread also does some operation that accesses the database.

One of the threads finishes its work and disposes its UnitOfWork. When the other thread hasn't finished yet, it crashes with an exception that says "You are not in a unit of work".

Something doesn't seem to be thread safe (I'm guessing the session, but it's just a guess). Do you have any clue?
Left by Hans Melis on Jun 04, 2009 4:09 AM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
>>Something doesn't seem to be thread safe (I'm guessing the session, but it's just a guess). Do you have any clue?

The NHibernate session defenitly is not thread safe.
Left by Carsten on Jun 24, 2009 12:44 AM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
Can someone please solve the thread safe issue!
Left by Jopo on Jul 15, 2009 10:04 PM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
The Unit Of Work factory has been incorrectly implemented. The CurrentSession property in the UnitOfWorkFactory should be getting/setting ISession from the Local hashtable instead of storing it as a private static variable. Please see Ayande's RhinoCommons implementation of the unit of work, from which this has been derived from.
Left by Bob on Jul 18, 2009 4:51 PM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
Well, I would want to say "good article", but unfortunately I can not. All three parts of this were quite poor. The author for some reason keeps on deviating from the main point of interest here - Unit of work and keeps spending way too much time on TDD, writing more about TDD than the issue at hand. This is a very poor practice and shows that the author has never tried to teach anyone anything - you should keep to the point and be very clear about your intentions. I do not want to read about why you use reflection in your tests - I want to hear about reasons for making something internal/private/protected. I don't care about which mock framework you use, I care about ideas behind UoW, thoughts behind this implementation.

Why bother with hashtables to "store something else"? KISS! This is related to UoW - do not store anything else in there!

Also, why re-invent the wheel if this is a simple rip-off of Aydene's work? What did you bring into it to make it worthwhile?

Sorry for being so harsh, but this is an important topic and having poor articles on official nHibernate web-site is a mistake - a lot of people will end up shooting themselves in a foot by reading this.
Left by Alex on Jul 20, 2009 4:54 AM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
Does this work?
Left by Kevin on Oct 16, 2009 1:21 AM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
I like the fact that strips out a lot of Ayende's stuff as I'm new to .NET & NHibernate so am finding his code too complex.

Does this implementation work so I can use it for my project?

Regards
Kevin
Left by Kevin on Oct 16, 2009 1:35 AM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
Good explanation, thank you.
Left by work at home blog on Nov 26, 2009 9:38 PM

# SEO India

Requesting Gravatar...
SEO India
Left by SEO India on Dec 05, 2009 4:53 AM

# Pontins

Requesting Gravatar...
Pontins
Left by Pontins on Dec 05, 2009 4:54 AM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
thank you.
Left by pandora jewelry on Dec 24, 2009 11:53 PM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
I have a question...Why in your design you tie the UoW factory interface to the Hibernate ISession (IUnitOfWorkFactory.CurrentSession)?, at the beginning of the article you claim that the idea of your design is to abstract the data manipulation from a specific infrastructure (ex. NHibernate, EF, Memory, etc) otherwise you can use ISession in a simple way, so, unless I miss something, it seems the original design goal is broken.
Left by brand new casinos on Dec 30, 2009 10:16 PM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
Thanks for the hint, I was looking for sth. like that for months :-)
Left by Larry blog on Jan 12, 2010 9:04 AM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
best thanks
Left by make money online on Jan 16, 2010 1:15 PM

# re: NHibernate and the Unit of Work pattern (Part 3)

Requesting Gravatar...
What's more, a bracelet can also be equipped with different small pandora jewelry and even you can change it according to your mood at any time. Here are some meanings of pendant. Small Plane stands for traveling and adventure ; anchor, stability and hope; your baby's boots, having a lot of babies; small feeding pandora bracelets abundant food; Church means happiness and stability of marriage; dragonfly means riches; Eiffel Tower means travel and exploration; four-leaf clover means fortune; horseshoe means luck; Nest means a happy family; bride shows a happy bride in her coming pandora jewelleryship steering shows calming and confidence; pandora ukcoin shows rich marriage life. Wish bone, dreams being about to come true; pandora charm bracelets, love; one heart shot by an arrow, romantic love; purse, wealth; and heart-shaped lock, true love.
Left by kasandra1972 on Jan 29, 2010 12:46 PM

# re: NHibernate and the Unit of Work pattern (Part 3)

Left by ugg boot on Feb 08, 2010 7:07 PM

Your comment:

 (will show your gravatar)
 
Please add 1 and 4 and type the answer here: