Using the unit of work-per-request pattern in ASP.NET MVC

In this post I describe a simple, efficient and testable approach to implementing the unit of work-per-request (a.k.a session-per-request) pattern in Microsoft’s new ASP.NET MVC framework. I provide a sample implementation that uses LightSpeed 2 but the principles are broadly applicable to other unit of work style O/RMs.

Unit of Work Primer

For those unfamiliar with the Unit of Work pattern here’s Mr Fowler’s definition:

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

A unit of work is really just a way of keeping of track of a set of entities that have been loaded into memory. Once loaded, we can work with the entities in the normal way: changing state, adding new entities and removing other entities. When we are ready to save our changes we ask the unit of work to commit and it takes care of “flushing” the pending changes to the underlying database.

Managing Unit of Work Scope in Web Applications

In LightSpeed a unit of work is primarily two things:

  • An ADO.NET connection to the underlying database.
  • An Identity Map referencing the entities associated with this unit of work.

An important consideration when developing web applications that use an O/RM solution is how to manage unit of work scope. Given that a unit of work holds a database connection we ideally want to minimize how many we create. We also want each unit of work to be disposed as soon as it’s no longer needed thus freeing up server resources.

The unit of work-per-request pattern is a common solution that says we should use one unit of work instance for each web request.

An ASP.NET MVC & LightSpeed Implementation

Let’s take a look at a possible implementation using the popular Northwind product catalog ASP.NET MVC sample application.

First we create a global singleton LightSpeedContext object that contains our configuration and acts as a factory for creating concrete unit of work instances.

// Global.asax.cs
 
public static readonly LightSpeedContext<NorthwindUnitOfWork> LightSpeedContext
  = new LightSpeedContext<NorthwindUnitOfWork>
  {
    ConnectionString = "My Connection String",
    PluralizeTableNames = true,
    IdentityMethod = IdentityMethod.IdentityColumn,
    Logger = new TraceLogger()
  };

Next we encapsulate the concept of a “scope” for managing the lifetime of a single unit of work instance. When running inside ASP.NET MVC we want this scope to be “per request”. Consequently, we use the HttpContext.Items collection to stash our IUnitOfWork instance.

// PerRequestUnitOfWorkScope.cs
 
public sealed class PerRequestUnitOfWorkScope<TUnitOfWork> : UnitOfWorkScopeBase<TUnitOfWork>
  where TUnitOfWork : class, IUnitOfWork, new()
{
  private const string ItemsKey = "__LightSpeedUnitOfWork__";
 
  public PerRequestUnitOfWorkScope(LightSpeedContext<TUnitOfWork> lightSpeedContext)
    : base(lightSpeedContext)
  {
  }
 
  public override TUnitOfWork Current
  {
    get
    {
      var current = (TUnitOfWork)HttpContext.Current.Items[ItemsKey];
 
      if (current == null)
      {
        HttpContext.Current.Items[ItemsKey] = current = LightSpeedContext.CreateUnitOfWork();
      }
 
      return current;
    }
  }
 
  public override bool HasCurrent
  {
    get { return HttpContext.Current.Items.Contains(ItemsKey); }
  }
}

Now we need to ensure that our controllers perform data access operations through the current unit of work defined on our per-request scope. A good approach for decoupling controllers from concrete data access code is to use the Repository pattern. Let’s go with that. Here’s what a repository for our product catalog looks like:

// ICatalogRepository.cs
 
public interface ICatalogRepository : IRepository
{
  Category GetCategory(int id);
  Product GetProduct(int id);
 
  void Add(Product product);
 
  IEnumerable<Category> Categories { get; }
  IEnumerable<Supplier> Suppliers { get; }
}

The repository is used from our ProductsController like so:

// ProductsController.cs
 
private readonly ICatalogRepository _catalogRepository;
 
public ActionResult Category(int id)
{
  var category = _catalogRepository.GetCategory(id);
 
  return RenderView("List", category);
}
 
// More actions..

We’re clearly going to need a concrete implementation of our ICatalogRepository. The primary role of this class is to encapsulate LightSpeed specific data access requests. Additionally, it gives us a good place to inject our per-request scope logic defined above:

public CatalogRepository(UnitOfWorkScopeBase<NorthwindUnitOfWork> unitOfWorkScope)
: base(unitOfWorkScope)
{
}
 
public Category GetCategory(int id)
{
  return _unitOfWorkScope.Current.FindOne<Category>(id);
}
 
public Product GetProduct(int id)
{
  return _unitOfWorkScope.Current.FindOne<Product>(id);
}
 
public void Add(Product product)
{
  _unitOfWorkScope.Current.Add(product);
}
 
public IEnumerable<Category> Categories
{
  get { return _unitOfWorkScope.Current.Find<Category>(); }
}
 
public IEnumerable<Supplier> Suppliers
{
  get { return _unitOfWorkScope.Current.Find<Supplier>(); }
}

Given that this pattern will be consistent across our application, we factor the scope code up to a base class:

public abstract class RepositoryBase : IRepository
{
  protected UnitOfWorkScopeBase<NorthwindUnitOfWork> _unitOfWorkScope;
 
  protected RepositoryBase(UnitOfWorkScopeBase<NorthwindUnitOfWork> unitOfWorkScope)
  {
    _unitOfWorkScope = unitOfWorkScope;
  }
 
  public void SaveChanges()
  {
    _unitOfWorkScope.Current.SaveChanges();
  }
}

The last piece of the puzzle is how to tie together our controllers and repositories. For simplicity we just do this:

// ProductsController.cs
 
public ProductsController()
{
  _catalogRepository = new CatalogRepository(UnitOfWorkScope);
}

UnitOfWorkScope is a property exposed by our base controller class like so:

// ControllerBase.cs
 
private UnitOfWorkScopeBase<NorthwindUnitOfWork> _unitOfWorkScope;
 
public UnitOfWorkScopeBase<NorthwindUnitOfWork> UnitOfWorkScope
{
  get
  {
    if (_unitOfWorkScope == null)
    {
      _unitOfWorkScope = new PerRequestUnitOfWorkScope<NorthwindUnitOfWork>(Global.LightSpeedContext);
    }
 
    return _unitOfWorkScope;
  }
}
 
protected override void OnResultExecuted(ResultExecutedContext filterContext)
{
  if (_unitOfWorkScope != null)
  {
    _unitOfWorkScope.Dispose();
   }
}

As illustrated above, we override OnResultExecuted to ensure that our IUnitOfWork is correctly disposed at the end of each request.

Testability

A key aspect of this approach is that it facilitates testability. The two key pieces that enable testability are:

  • We’ve encapsulated our unit of work scope into a pluggable dependency – think strategy pattern.
  • Our controllers depend on repositories and not concrete LightSpeed code.

To enable easy controller testing we can just add the following constructor to our controllers:

// ProductsController.cs
 
public ProductsController(ICatalogRepository catalogRepository)
{
  _catalogRepository = catalogRepository;
}

With this in place we can instantiate a controller bypassing the normal scoping arrangement. A controller unit test may look something like this:

// ProductControllerUnitTests.cs
 
[Test]
public void ExampleUnitTest()
{
  var controller = new ProductsController(new FakeCatalogRepository());
 
  Assert.IsNotNull(controller.Category(1));
}

We can also create integration style tests that actually perform real work. For these we can create another scope implementation more appropriate for testing. Our tests might look something like:

// ProductControllerIntegrationTests.cs
 
private SimpleUnitOfWorkScope<NorthwindUnitOfWork> _unitOfWorkScope;
 
[SetUp]
public void SetUp()
{
  _unitOfWorkScope = new SimpleUnitOfWorkScope<NorthwindUnitOfWork>(_lightSpeedContext);
}
 
[Test]
public void ExampleIntegrationTest()
{
  var controller = new ProductsController(new CatalogRepository(_unitOfWorkScope));
 
  Assert.IsNotNull(controller.Category(1));
}

where SimpleUnitOfWorkScope is just:

public sealed class SimpleUnitOfWorkScope<TUnitOfWork> : UnitOfWorkScopeBase<TUnitOfWork>
  where TUnitOfWork : class, IUnitOfWork, new()
{
  private TUnitOfWork _current;
 
  public SimpleUnitOfWorkScope(LightSpeedContext<TUnitOfWork> lightSpeedContext)
    : base(lightSpeedContext)
  {
  }
 
  public override TUnitOfWork Current
  {
    get
    {
      if (_current == null)
      {
        _current = LightSpeedContext.CreateUnitOfWork();
      }
 
      return _current;
    }
  }
 
  public override bool HasCurrent
  {
    get { return _current != null; }
  }
}

If anyone wants a sample download then let me know and I’ll put it together.

kick it on DotNetKicks.com

Tagged as General, LightSpeed

12 Responses to “Using the unit of work-per-request pattern in ASP.NET MVC”

Archives

Join our mailer

You should join our newsletter! Sent monthly:

Back to Top