ASP.NET MVC 3: How to use the Unit of Work pattern with Unity 2.0

Update 2013-04-18 I’ve updated the EndRequest event handler to only commit the changes if no error occurred in the current HTTP request.

In one of my last post, I showed how to set up the Unity 2.0 dependency injection container in an ASP.NET MVC 3 web application.
In this post, I will show how to use the Unit of Work pattern in combination with the Unity dependency resolver in an ASP.NET MVC 3 web application. The Unit of Work pattern is described by Martin Fowler as follows:

Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.

In a web application writing changes to the database is typically done at the end of each request. To accomplish this, we need to create an instance of the Unit of Work implementation for each request, share this instance in all business objects (i.e. use Unity to inject the Unit of work into the business objects) and commit the changes at the end the request. The concrete implementation of the Unit of Work pattern is not part of this post (you can find more information on other pages like “Using Repository and Unit of Work patterns with Entity Framework 4.0″).
In the following I will give step-by-step instructions how to integrate the Unit of Work in your ASP.NET MVC 3 web application. First we first need an implementation of Unity’s LifetimeManager class that makes sure that the Unit Of Work instance lives exactly for one request (I’m using an implementation found in this post):

public class HttpContextLifetimeManager<T> : LifetimeManager, IDisposable
{
  public override object GetValue()
  {
    return HttpContext.Current.Items[typeof(T).AssemblyQualifiedName];
  }
  public override void RemoveValue()
  {
    HttpContext.Current.Items.Remove(typeof(T).AssemblyQualifiedName);
  }
  public override void SetValue(object newValue)
  {
    HttpContext.Current.Items[typeof(T).AssemblyQualifiedName] = newValue;
  }
  public void Dispose()
  {
    RemoveValue();
  }
}

The remaining configuration is done in the Global.asax file:

  • Configure the Unity container in the Application_Start method and use the HttpContextLifetimeManager (see above) when registering the Unit of Work type (the interface is typically named IUnitOfWork). The implementation of the UnityDependencyResolver used in the example code below can be found in one of my previous post “ASP.NET MVC 3: Dependency injection with Unity 2.0“.
  • In the constructor of your MVC application, register an event handler for the “end request” event and use the Unit of Work to commit all changes to the database.
  • Of course, you have to inject the Unit of Work instance to all business objects that do database changes, e.g. by using Unity’s constructor or property injection.

The important parts of the Global.asax.cs are shown below:

public YourMvcApplication()
{
  [...]
  EndRequest += new EventHandler(GlobalApplication_EndRequest);
}
 
protected void Application_Start()
{
  [...]
  var container = new UnityContainer();
  container.RegisterType<IUnitOfWork, ConcreteUnitOfWork>(new HttpContextLifetimeManager<IUnitOfWork>());
  [...]
  DependencyResolver.SetResolver(new UnityDependencyResolver(container));
  [...]
}
 
void GlobalApplication_EndRequest(object sender, EventArgs e)
{
  if (HttpContext.Current.Error != null) return;
  var unitOfWork = _container.Resolve<IUnitOfWork>();
  unitOfWork.Save();
}

Comments

  1. Daniel

    Not sure I agree with the Save method in the EndRequest event. You may not always be committing changes. Great article though!

  2. Jan Jonas

    Hi Daniel,
    thanks for your comment. Do you have any example where you do not want to commit the data to persist them in the database? Spontaneous I can image, that it could be reasonable to skip committing changes when returning an error to the client (for example a HTTP status code 401 “Unauthorized”) to ensure that these requests don’t change the database.

  3. Daniel

    If I make a query request rather than a change/insert request, why would I want to save changes? Seems like extra overhead. Leave it up to the BL to determine persisting rather than a global commit. I do agree with disposing, but if you use your custom lifetime manger above, the UoW should be losing reference anyway, correct? So, not sure you even need to dispose.

  4. Jan Jonas

    Hi Daniel,
    thanks again for your comment. IMHO, saving changes when there are actually no changes shouldn’t be expensive or time consuming. I think implementing your own logic to decide whether to save the changes or not is not more efficient than leaving the decision to the ORM. Moreover, I think saving changes inside the business logic could raise other problems: If you call two different methods in your business logic to process one request and both methods save the changes independently, the second method could fail and the changes of the first method call are already persisted in the database. Of course, this could be a desirable result, but in general, for web applications I prefer implementation that uses one transaction for each request to update the database .

Leave a comment

Your email address will not be published. Required fields are marked *

*