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

Your comment:

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