Thursday, October 25, 2012

EntityFramework context per request-lifetime thread-safe with Unit Tests

When using EntityFramework, you need a consistent way to manage the context object lifecycle. The most accepted way to do this is creating a context per HTTP Request


I´m going to show you a basic thread-safe implementation.


Building the component


Context Resolver Contract


public interface IContextResolver
{
    TContext GetCurrentContext<TContext>() where TContext : DbContext;

    void ReleaseContext();
}

This interface is really simple, it just defines two methods.


  • The GetCurrentContext method will be used to get or create the EntityFramework context object.

  • The ReleaseContext method will be in charge to call Dispose in your context in order to release resources.


Context Resolver implementation


public class ContextResolver : IContextResolver
{
    private static object syncRoot = new Object();
    private string connectionString;
    private volatile HttpContextBase httpContextBase;
    private const string ContextItemName = "Context_Per_Request";

    public ContextResolver(HttpContextBase httpContext, string connectionString)
    {
        Condition.Requires(httpContext).IsNotNull();
        Condition.Requires(connectionString).IsNotNullOrWhiteSpace();

        this.connectionString = connectionString;
        this.httpContextBase = httpContext;
    }

    public TContext GetCurrentContext<TContext>() where TContext : DbContext
    {
        TContext context = default(TContext);

        lock (syncRoot)
        {
            context = this.httpContextBase.Items[ContextItemName] as TContext;
        }

        if (context == null)
        {
            lock (syncRoot)
            {
                if (context == null)
                {
                    context = (TContext)Activator.CreateInstance(typeof(TContext), this.connectionString);
                    this.httpContextBase.Items.Add(ContextItemName, context);
                }
            }
        }

        Condition.Ensures(context).IsNotNull().IsOfType(typeof(TContext));
        return context;
    }

    public void ReleaseContext()
    {
        DbContext context = default(DbContext);

        lock (syncRoot)
        {
            context = this.httpContextBase.Items[ContextItemName] as DbContext;
        }

        if (context != null)
        {
            context.Dispose();
        }
    }
}

The implementation is straightforward, the only tricky part is the addition of lock statements when reading and writing the EntityFramework context.


The C# specification clearly defines what operations are "atomic" in section 5.5. The atomic operations are reads and writes of variables of any reference type, or, effectively, any built-in value type that takes up four bytes or less


Source


In order to implement the context per HTTP request pattern, we use HttpContext.Items. The objects we store in this dictionary, will be accessible only during the current HTTP request.


Gets a key/value collection that can be used to organize and share data between an IHttpModule interface and an IHttpHandler interface during an HTTP request.


Usage


You just have to configure your DI container (if any) to inject the correct instance of IContextResolver.


Injecting


For simplicity I will inject it in my MVC controller


private IContextResolver contextResolver;

public HomeController(IContextResolver contextResolver)
{
    this.contextResolver = contextResolver;
}

public ActionResult SimpleData()
{
    var ctx = this.contextResolver.GetCurrentContext<pubsEntities>();

    return View(ctx.jobs);
}

In Global.asax


During the whole request, all the calls to IContextResolver.GetCurrentContext are going to return the same context instance, we now need to dispose the context after the request has been processed. We can do this in the PostRequestHandlerExecute application event in the Global.asax file.


public MvcApplication()
{
    this.PostRequestHandlerExecute += MvcApplication_PostRequestHandlerExecute;
}

void MvcApplication_PostRequestHandlerExecute(object sender, EventArgs e)
{
    var resolver = ServiceLocator.Current.GetInstance<IContextResolver>();

    resolver.ReleaseContext();
}

Notice the use of the ServiceLocator... your first impression might be: “hey dude, that’s an anti-pattern”...


Most of the time it is an anti-pattern, but in this case, we are using it inside the Composition Root Object of the Web Application, therefore we are allowed to use the container, actually I could change the code to use directly my DI container (Ninject - Kernel in this case), but this will get me the same result, even though, I would be adding an explicit dependency to Ninject.


Unit Testing


It’s time to show you the unit tests I created for this small but useful component


Builder


I tend to use builders to create my SUT objects, it seems like a consistent way to create testing objects


public class ConcreteResolverBuilder
{
    private ContextResolver Instance { get; set; }

    private static volatile HttpContextBase httpContextBase;
    private static volatile Dictionary<string, object> items;
    private static object syncRoot = new Object();

    public static HttpContextBase HttpContextBase
    {
        get
        {
            if (httpContextBase == null)
            {
                lock (syncRoot)
                {
                    if (httpContextBase == null)
                    {
                        var mock = new Mock<HttpContextBase>();

                        items = new Dictionary<string, object>();
                        mock.Setup(x => x.Items).Returns(items);

                        httpContextBase = mock.Object;
                    }
                }
            }

            httpContextBase.Should().NotBeNull();
            return httpContextBase;
        }
    }

    public ConcreteResolverBuilder Initialize()
    {
        this.Instance = new ContextResolver(
            HttpContextBase,
            ConfigurationManager.ConnectionStrings["Msts"].ConnectionString);

        return this;
    }

    public ContextResolver Build()
    {
        this.Instance.Should().NotBeNull();
        return this.Instance;
    }

    public static implicit operator ContextResolver(ConcreteResolverBuilder builder)
    {
        return builder.Build();
    }
}

I´m implementing a singleton pattern just because I want to mock an HttpContextBase object to simulate a real HTTP request


I´m also configuring the HttpContextBase.Items properties with Moq to return a Dictionary object


Note that since my intention is to simulate concurrent threads, I'm marking my HttpContextBase and Dictionary members as volatile


The Tests


[TestClass]
public class ContextResolverTests
{
    [TestClass]
    public class TheCreateContextInstanceMethod
    {
        [TestMethod]
        public void it_should_resolve_a_valid_instance()
        {
            ContextResolver sut = new ConcreteResolverBuilder().Initialize();
            var res = sut.GetCurrentContext<PubsContext>();

            res.Should().NotBeNull().And.BeOfType<PubsContext>();
        }

        [TestMethod]
        public void it_should_return_the_same_instance_even_when_calling_it_from_different_threads()
        {
            ContextResolver sut = new ConcreteResolverBuilder().Initialize();
            var firstResolvedContext = sut.GetCurrentContext<PubsContext>();
            var numberOfConcurrentProcess = 10000;
            var contextResolverInstances = new BlockingCollection<DbContext>();
            var tasks = new Task[numberOfConcurrentProcess];

            for (int i = 0; i < numberOfConcurrentProcess; i++)
            {
                tasks[i] = Task.Factory.StartNew(() =>
                {
                    var context = new ConcreteResolverBuilder().Initialize().Build().GetCurrentContext<PubsContext>();

                    contextResolverInstances.Add(context);
                }, TaskCreationOptions.LongRunning);
            }

            Task.WaitAll(tasks);

            contextResolverInstances
                .Should()
                    .NotBeNull()
                .And
                    .NotBeEmpty()
                .And
                    .HaveCount(numberOfConcurrentProcess)
                .And
                    .ContainItemsAssignableTo<DbContext>()
                .And
                    .NotContainNulls();

            var firstResolvedContextHashCode = (firstResolvedContext as object).GetHashCode();

            firstResolvedContextHashCode.Should().NotBe(default(int));

            foreach (var item in contextResolverInstances)
            {
                var itemHashCode = (item as object).GetHashCode();

                itemHashCode.Should().NotBe(default(int));
                itemHashCode.Should().Be(firstResolvedContextHashCode);
                item.Should().Be(firstResolvedContext);

                var areReferenceEquals = ReferenceEquals(item, firstResolvedContext);

                areReferenceEquals.Should().BeTrue();
            }
        }
    }
}

  • The first test is really simple, it just ensures that we can create a context

  • The second test is more interesting, this is where I’m actually testing the concurrency of my implementation.


    • I keep track of the first context created to compare all subsequent contexts with this one.


      var firstResolvedContext = sut.GetCurrentContext<PubsContext>();
      
    • I set the number of concurrent operations


      var numberOfConcurrentProcess = 10000;
      
    • Now I create a list to store all the created contexts. Note that I’m using the BlockingCollection object which is thread-safe


      var contextResolverInstances = new BlockingCollection<DbContext>();
      
    • I’m storing all the parallel tasks in an array


      var tasks = new Task[numberOfConcurrentProcess];
      
    • I create and start all the tasks. On each task, I’m creating a new instance of my SUT (my concrete implementation of: IContextResolver) and adding to contextResolverInstances the result of IContextResolver.GetCurrentContext. Also note that I'm using: TaskCreationOptions.LongRunning to force the TPL to run my tasks in background threads


      for (int i = 0; i < numberOfConcurrentProcess; i++)
                  {
                      tasks[i] = Task.Factory.StartNew(() =>
                      {
                          var context = new ConcreteResolverBuilder().Initialize().Build().GetCurrentContext<PubsContext>();
      
                          contextResolverInstances.Add(context);
                      }, TaskCreationOptions.LongRunning);
                  }
      
    • I wait for all the tasks to complete by calling:


      Task.WaitAll(tasks);
      
    • The rest of the code are assertions, to confirm that just one instance was created among all threads




In the next screenshot you can see how the tasks are being executed on different threads





3 comments:

If you found this post useful please leave your comments, I will be happy to hear from you.