I have read as many of the posts on Stackoverflow as I can find with regards the use of a Unit of Work pattern within
an ASP.Net MVC 3 application which includes a Business Layer. However, I still have a couple of questions with
regards this topic and would greatly appreciate any feedback people can give me.
I am developing an ASP.Net MVC 3 Web application which uses EF 4.1. I will be using both the Repository and
Unit of Work Patterns with this project similar to how they are used in this great tutorial
The difference in my project is that I need to also include a Business Layer (separate project in my solution) in order to
carry out the various business rules for the application. The tutorial mentioned above does not have a Business layer, and
therefore creates an instance of the Unit of Work class from the controller
public class CourseController : Controller
{
private UnitOfWork unitOfWork = new UnitOfWork();
However, my question is, where should I create the instance of the Unit of Work class if I have a Business Layer?
I personally think it should be created in my controller and then injected into the Business Layer like so:
public class PeopleController : Controller
{
private readonly IUnitOfWork _UoW;
private IPersonService _personService;
public PeopleController()
{
_UoW = new UnitOfWork();
_personService = new PersonService(_UoW);
}
public PeopleController(IUnitOfWork UoW, IPersonService personService)
{
_UoW = UoW;
_personService = personService;
}
public ActionResult Edit(int id)
{
Person person = _personService.Edit(id);
return View(person);
}
public class UnitOfWork : IUnitOfWork, IDisposable
{
private BlogEntities _context = new BlogEntities();
private PersonRepository personRepository = null;
public IPersonRepository PersonRepository
{
get
{
if (this.personRepository == null)
{
this.personRepository = new PersonRepository(_context);
}
return personRepository;
}
}
public void Save()
{
_context.SaveChanges();
}
public class PersonService : IPersonService
{
private readonly IUnitOfWork _UoW;
public PersonService(IUnitOfWork UoW)
{
_UoW = UoW;
}
public Person Edit(int id)
{
Person person = _UoW.PersonRepository.GetPersonByID(id);
return person;
}
public class PersonRepository : IPersonRepository
{
private readonly BlogEntities _context;
public PersonRepository(BlogEntities context)
{
_context = context;
}
public Person GetPersonByID(int ID)
{
return _context.People.Where(p => p.ID == ID).Single();
}
I have read others saying that the Unit of Work instantiation should not be in the Controller, but created in the Service Layer
instead. The reason why I am not so sure about this approach is because my Controller may have to use several different
Service Layers in one business transaction, and if the Unit of Work instance was created inside each Service, it would result in several
Unit of Work instances being created, which defeats the purpose, ie, one Unit of Work per business transaction.
Maybe what I have explained above is wrong, but if so, I would greatly appreciate if someone could put me right.
Thanks again for your help.
I think you have a couple of changes to make:.
Allow your DI container to inject a
UnitOfWorkinstance into your Service classes in their constructors, and leave it out of your Controller altogether.If your DI container supports it (Ninject does, for example), configure your
UnitOfWorkto be managed on a per-request basis; this way your services will be handed a distinctUnitOfWorkfor each request, and you’re all done. Or…If your DI container does not support per-request lifetimes, configure it to manage the
UnitOfWorkas a singleton, so everyServiceclass gets the same instance. Then update yourUnitOfWorkto store itsEntitiesobject in a data store which stores objects on a per-request basis, for example inHttpContext.Current.Items, as described here.Edit 1
Regarding where the
UnitOfWorkshould be injected; I’d say the Service layer is the correct place. If you imagine your system as a series of layers where the outer layers deal with user interactions and the lower layers deal with data storage, each layer should become less concerned with users and more concerned with data storage.UnitOfWorkis a concept from one of the ‘lower-level’ layers and Controller is from a higher-level layer; yourServicelayer fits between them. It therefore makes sense to put theUnitOfWorkinto theServiceclass rather than theController.Edit 2
To elaborate on the
UnitOfWorkcreation and it’s relationship toHttpContext.Current.Items:Your
UnitOfWorkwould no longer hold a reference to anEntitiesobject, that would be done through theHttpContextobject, injected into theUnitOfWorkbehind an interface like this:The
HttpContextobject would then implementIPerRequestDataStorelike this:As an aside, I’ve called it
StaticHttpContextPerRequestDataStoreas it uses the staticHttpContext.Currentproperty; that’s not ideal for unit testing (another topic altogether), but at least the name indicates the nature of its dependency.Your
UnitOfWorkthen passes theIPerRequestDataStoreit’s given to each of itsRepositoryobjects so they can access theEntities; this means that no matter how manyUnitOfWorkinstances you create, you’ll use the sameEntitiesobject throughout a request because it’s stored and retrieved in theIPerRequestDataStore.You’d have an abstract base
Repositorywhich would use itsIPerRequestDataStoreto lazy-load itsEntitiesobject like this:Your
PeopleRepository(for example) would look like this:And finally, here’s the creation of your
PeopleController:One of the central concepts here is that objects have their dependencies injected into them via their constructors; this is generally accepted as good practice, and more easily allows you to compose objects from other objects.