ASP.NET MVC, DataContext and The Unit of Work Pattern

An entry about asp.net mvc | design patterns Publication date 17. May 2008 15:33

Previously, I talked about the Repository pattern and how we could implement it using Linq (and Linq to Sql in particular). This week, I'd like to take the Linq Repository abstraction that I came up with last time, and show how we can use it to easily and transparently enable the Unit of Work pattern, using ASP.NET MVC as our host.

What's in a Unit

From Fowler, a Unit of Work "maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems" (PEAA, p. 184). The key here is that "unit" means "business transaction".

The Linq to Sql DataContext is designed perfectly to support this pattern. In fact, the MSDN documentation for it plainly states that "a DataContext instance is designed to last for one "unit of work" however your application defines that term. A DataContext is lightweight and is not expensive to create. A typical LINQ to SQL application creates DataContext instances at method scope or as a member of short-lived classes that represent a logical set of related database operations." .NET consultant and author (MSDN Magazine) Dino Esposito emphasises this point in an in-depth article over at DotNetSlackers, and also in a follow-up post on his blog.

One Request = One Action = One Unit of Work

The beauty of an MVC application, is that each request is self-contained. There's no state to worry about; each request has all the information it needs to carry out the requested action. This fits neatly with what we've just discussed - we can then say that each request, or action, is in fact a single unit of work.

I've talked about how to set up the IOC container Autofac for ASP.NET MVC before, so I won't reiterate that here. The cool thing about Autofac, is that it allows for nested containers. In fact, its ASP.NET integration module will out of the box set up a root container that is application scoped, and then a new nested container for each new request. All we have to do then, is to register our IDataContext as a container scoped object. Autofac will then ensure that throughout the lifetime of any request, any object that asks for it gets the same IDataContext instance injected:

builder.Register(c => new DataContext(ConfigurationManager.ConnectionStrings["SqlServer"].ConnectionString)).FactoryScoped();
builder.Register<LinqToSqlContext>().As<IDataContext>().ContainerScoped();

 

Notice that I've registered the concrete DataContext class as well - this is so that Autofac will know how to resolve the constructor for my LinqToSqlContext, which takes a DataContext as its single parameter.

Any controller class that has actions which require access to the unit of work can then be implemented like this:

public class EditController : Controller
{
    private readonly IDataContext _unitOfWork;
 
    public EditController(IDataContext unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }
 
    public ActionResult Rename(string route, string newTitle)
    {
        IPage page = _unitOfWork.Repository<IPage>().Where(p => p.Route.Path == route).Single();
        page.Title = newTitle;
 
        return new RenderJsonResult {Result = new {status = "ok"}};
    }
 
    protected override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        base.OnActionExecuted(filterContext);
        _unitOfWork.Commit();
    }
}

 

Note that I would probably move that OnActionExecuted method to a base controller type to avoid duplicating it in all my controllers. And also note that because of the deterministic disposal functionality of Autofac, we don't have to worry about disposing the IDataContext; it (and the Linq to Sql DataContext it wraps) will be disposed with the nested container at the end of the request.

I think the power of design patterns really shows when you see how well different technologies that adhere to them are then enabled to work together in perfect harmony, like here.

Currently rated 4.2 by 6 people

  • Currently 4.166667/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Comments

Powered by BlogEngine.NET 1.4.5.0

Welcome!

My name is Fredrik Kalseth, and this is my blog - thanks for visiting! I am fortunate enough to work with what I love for a living, and this blog is essentially the biproduct of that.

I work as a senior consultant for Capgemini, and am also an active participant in the Norwegian .NET community, as an avid attendee but also as a speaker (most recently at NNUG and MSDN Live).

As a developer, I have a wide circle of interest. My primary passion is for agile, test-driven development, with focus on best practices and clean code. That said, I also love to work on the frontend, especially with web development.

On Twitter? My handle is fkalseth. On LinkedIn? I`m there too.

NDC 2010

The conference to attend this summer happens June 16th-18th in Oslo, Norway. Are you going? Be sure to catch my talk on AOP while you're there!

 

Disclaimer

This is a personal blog; any opinions expressed here are my own and do not necessarily reflect those of my employer. All content herein is my own original creation, and as such is protected by copyright law. Unless otherwise stated, all source code posted on this blog is freely usable under the Microsoft Permissive License.

What Readers Talk About

Comment RSS