Should the Unit of Work by used by the service layer or the repository?

Hello, here a nice debate.

In an ASP.NET MVC3 environnement with entity framework. Should the Unit of Work point to the service layer or the repository (and then the repository point to the service layer) ?

Ive saw two example:

* One where the unit of work and repository both have an instance to the service layer..

Link: Entity Framework 4 CTP 4 / CTP 5 Generic Repository Pattern and Unit Testable

Doesn’t use a service layer but its obvious that one could be use in that case.

* Second where the unit of work have an instance to the repository which have an instance to the service layer..

Link: http://blogs.msdn.com/b/adonet/archive/2009/06/16/using-repository-and-unit- of-work-patterns-with-entity-framework-4-0.aspx

What would be better ? and why ?

Thanks.

I’ll join the debate!

Actually, I see the UnitOfWork pattern raise it’s head in many situations, not just regarding persisting entities. Basically you would want to use this pattern any time something needs to done in a batch where the entire batch succeeds or fails.

But you’re right, more often than not, it’s while performing persistence. The way I see it, the entire request can be considered a unit of work. I first got this idea during one of my NHibernate projects where I wanted to cache the ISession on a per-request basis to avoid cross session problems.

How I handle it is with static caching classes that wrap calls to HttpContext.Current.Items for both an ISession and an ITransaction object. I set these up, commit them, and dispose of them in Application_BeginRequest and Application_EndRequest. All repository implementation use SessionProvider.Current and TransactionProvider.Current internally. This way, you don’t have to worry about cross session problems and your transaction is committed or rolled back on error during EndRequest. There is no longer any need to implement the UnitOfWork pattern within a given Action.

Now, let’s wait and see how others handle this. I’m sure they’ll be different. =)

Ive heard of that solution. However, its seem kind of odd with Entity Framework. There no way to rollback. The UoW seem to be used only for commits. Plus the whole system seem integrated in EF (using SaveChanges). I am wrong ?

I’m using plain old Ado.Net for database stuff all wrapped up in a repository. So my UoW is implemented via sql transactions at repository level. Not ideal for some cases but overall it works .

Ive seen many example which was using the unit of work at the repository level and actually i guess this aint bad. I think the service layer afterall shouldnt know about it. But the repository is other story since it DO work with the context. What do you think ?

You are right Rush. With EF (and L2SQL), the context classes do lump commits and rollbacks into SaveChanges. The way to do this is:

using (var transaction = context.Connection.[COLOR=#2b91af]BeginTransaction/COLOR)
{

  [COLOR=#808080]// do something with context...[/COLOR]

  [COLOR=#00008b]try[/COLOR] 
  { 
       context.[COLOR=#2b91af]SaveChanges[/COLOR](); 
       transaction.[COLOR=#2b91af]Commit[/COLOR](); 
  } 
  [COLOR=#00008b]catch[/COLOR] ([COLOR=#2b91af]Exception[/COLOR] ex) 
  { 
       transaction.[COLOR=#2b91af]Rollback[/COLOR](); 
  } 

}

So you can still do transaction level stuff with ObjectContexts by wrapping your own transaction around the context’s inner transaction.

=)

Interresting. I wasn’t sure EF would have a way to begin a transaction. So now the idea is to implement this into the unit of work and then we have a viable solution.

However, i still have concerns about where to put the UoW.

1- If i put it in repository level, we have the problem where i can’t access others repository in the same transaction (which is rather bad after thinking about it) except if you persist the unit of work.

2- If i put it in the service layer… this fix the problem at 1. But the other problem is why the service layer should know about the UoW ?

3- Controller level, it isnt responsable about UoW actually so not a good idea.

Also i wonder if a wrapper could be used because repeater the transaction code would be a pain.

This is challenging since i am new to theses patterns and i need to come up with a solution for a project next week. But i almost figured out the architecture, the problem is only with the UoW.

Ok, here’s what I would probably do in your case. Use the EF object context as intended (a combination repository) wrapped in a UnitOfWork class.


public interface IUnitOfWork : IDisposable
{
ObjectContext Context { get; }
}
public class UnitOfWork : IUnitOfWork
{
private ObjectContext context;
private DbTransaction transaction;
public UnitOfWork()
{
context = new MyCustomContext();
transaction = context.Connection.BeginTransaction();
}
public ObjectContext Context
{
get { return context; }
}
public void Dispose()
{
try
{
context.SaveChanges();
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
}
}
}

Then use it like this:


using (IUnitOfWork uow = new UnitOfWork())
{
 
var post = new Post();
 
uow.Context.CreateObjectSet<Post>().AddObject(post);
 
}

Now you don’t even have to call SaveChanges. Whatever you do within the using block will be a single transaction.

Nice! Thanks for the example. Also, its been clear now that the Unit of Work belong to the service layer for many reasons.

First, it can’t belong to the repository because what you do if you need to access 2 repository ? That why the service will hold one or more repositories.

It can’t belong to the controller because that not his responsability.

The best option is the service layer offcourse… and with your addition that make a fully transaction capable solution. But like i said EF already support this out of the box because the context is an unit of work. But i guess there no implementation for rollback… so using your example you enable rolling back if something occur which is great.

Well, I gave you just the tip of the iceberg. There’s a lot more you can do with this pattern, including adding support for an “Inner” unit of work, allowing for nested transactions. You -could- also make your repositories implement IDisposable on their own. This works well if you adhere to the Domain Driven Design principal of having only one repository per aggregate chain, but I won’t get into that here. I’d suggest putting more research into the unit of work pattern and come up with a solution that fits your needs.

Yeah i believe but for my needs i believe putting more research into the uow pattern would be overkill. I just wanted something to start from. To have an idea of how everything workig together in an mvc 3 application. I am still at the stade of learning MVC so i won’t go into deeper detail. I think i passed like all the week into research of architecture solutions to go with MVC 3.

But your example gonna be useful, being able to do simple transaction is still great.

Do you use the MVC3 DependencyResolver for dependency injection? If so, I can give you further examples of how to bring this home.

Nah i use Ninject.

Not what I meant. You can use DependencyResolver with any injection container. I use it with both Castle.Windsor as well as Unity.

What it do ? It lets you use many DI Container ?

Yes. Here’s my UnityDependencyResolver for instance.


using System;
using System.Collections.Generic;
using System.Web.Mvc;
using Microsoft.Practices.Unity;
namespace BuzzBox.Infrastructure.Web.Resolvers
{
public class UnityDependancyResolver : IDependencyResolver
{
private IUnityContainer _unityContainer;
public UnityDependancyResolver(IUnityContainer unityContainer)
{
_unityContainer = unityContainer;
}
public object GetService(Type serviceType)
{
return _unityContainer.IsRegistered(serviceType) ? _unityContainer.Resolve(serviceType) : null;
}
public IEnumerable<object> GetServices(Type serviceType)
{
return _unityContainer.IsRegistered(serviceType) ? _unityContainer.ResolveAll(serviceType) : new List<object>();
}
}
}

And in Global.asax…


public static void RegisterComponents()
{
 
IUnityContainer container = new UnityContainer();
 
container.RegisterType<BuzzBoxController>();
container.RegisterType<HomeController>();
 
container.RegisterType<IContextProvider, WebContextProvider>();
 
container.RegisterType<IAvatarRepository, AvatarRepository>();
container.RegisterType<ICategoryRepository, CategoryRepository>();
container.RegisterType<ICommentRepository, CommentRepository>();
container.RegisterType<IMemberRepository, MemberRepository>();
container.RegisterType<IPostRepository, PostRepository>();
container.RegisterType<IRatingRepository, RatingRepository>();
container.RegisterType<ISubscriptionRepository, SubscriptionRepository>();
 
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
 
}

That’s it. You don’t need to setup a custom controller factory or anything. Additionally, you can also use the following anywhere in your mvc app to resolve something.


 
var IAvatarRepository = DependencyResolver.Current.GetService<IAvatarRepository>();
 

This makes things nice because you can now setup a unit of work like this…


public class UnitOfWork : IUnitOfWork
{
private ObjectContext context;
private DbTransaction transaction;
public UnitOfWork()
{
this.context = Resolve<IContextProvider>().GetCurrentContext();
this.transaction = context.Connection.BeginTransaction();
}
public T Resolve<T>()
{
return DependencyResolver.Current.GetService<T>();
}
public void Dispose()
{
try
{
context.SaveChanges();
transaction.Commit();
}
catch
{
transaction.Rollback();
}
}
}

And as long you also inject your repositories with IContextProvider, you can do this…


 
using (IUnitOfWork worker = new UnitOfWork())
{
 
// safely use any combination of repositories you want
var postRepository = worker.Resolve<IPostRepository>();
var userRepository = worker.Resolve<IUserRepository>();
 
}
 
 

Here’s the context provider…


public interface IContextProvider
{
 
void SetCurrentContext(ObjectContext context);
 
ObjectContext GetCurrentContext();
 
}
public class WebContextProvider : IContextProvider 
{
public void SetCurrentContext(ObjectContext context)
{
HttpContext.Current.Items["CurrentContext"] = context;
}
public ObjectContext GetCurrentContext()
{
return HttpContext.Current.Items["CurrentContext"] as ObjectContext;
}
}

Just set this up and tear it down in Global.asax using Application_BeginRequest and Application_EndRequest.

Nice stuff! Thanks. Will look into this.