I was recently asked how I get the context of “this” in the UoW relating to the current page request.
Before I get into the guts, I would like to provide a little context. My application has 20+ databases scattered across 4 machines.
IRepository<Customer> customerRepository; // customer database on server 1 IRepository<Package> packageRepository; // customer database on server 1 IRepository<Contact> contactRepository; // contact database on server 2
The “magic” if you will, happens in the global.asax. I was nosing around in Rhino.Commons for inspiration and adapted a technique I saw there. This is how it looks:
public class GlobalApplication : HttpApplication { private static IUnityContainer container; public GlobalApplication() { BeginRequest += new EventHandler(GlobalApplication_BeginRequest); EndRequest += new EventHandler(GlobalApplication_EndRequest); } protected void Application_Start(object sender, EventArgs e) { RegisterRoutes(RouteTable.Routes); container = new UnityContainer(); container.AddNewExtension<PolicyInjectorContainerExtension>(); container.AddNewExtension<HttpRequestLifetimeCoreContainerExtension>(); container.AddNewExtension<WebMvcContainerExtension>(); ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container)); } void GlobalApplication_BeginRequest(object sender, EventArgs e) { var unitOfWork = container.Resolve<IUnitOfWork>(); unitOfWork.Start(); } void GlobalApplication_EndRequest(object sender, EventArgs e) { var unitOfWork = container.Resolve<IUnitOfWork>(); unitOfWork.Commit(); } }
I register the UoW with an HttpRequestLifetimeManager so I get a new instance for each request.
Container.RegisterType<IUnitOfWork<ISession>,
NHibernateUnitOfWork>(new HttpRequestLifetimeManager());
public class NHibernateRepository<T> : IRepository<T> { protected ISession session; public NHibernateRepository(IUnitOfWork<ISession> unitOfWork) { session = unitOfWork.GetContextFor<T>(); } ... public virtual void Save(T obj) { session.Save(obj); } }
Now, this is all the context of an ASP.NET MVC Controller, but I have a similar issue for other (non-web) services. In that context I am using AOP and decorating a particular method with [UnitOfWork], which looks like:
public class UnitOfWorkCallHander : ICallHandler { private IUnitOfWork<ISession> unitOfWork; public UnitOfWorkCallHander(IUnitOfWork<ISession> unitOfWork) { this.unitOfWork = unitOfWork; } public int Order { get; set; } public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { unitOfWork.Start(); try { return getNext()(input, getNext); } finally { unitOfWork.Commit(); } } }
In that context I use a PerThreadLifetimeManager for the NHibernateUnitOfWork, and code ends up looking like:
[UnitOfWork] public void Process(Job job) { ... }
You know, there is really no reason why you couldn’t do the same thing in the MVC context. You could basically ditch the global.asax event hooha and just annotate the Controller task:
[UnitOfWork]
public ActionResult ControllerTaskThatRequiresUoW()
{
...
}
It’s more explicit than using the global.asax technique and it would allow you to specify different UoW behavior on each controller task:
[UnitOfWork(IsolationLevel.ReadCommitted] public ActionResult SomeTaskThatShouldNotReadUncommitedData() { } [UnitOfWork(IsolationLevel.ReadUncommitted)] public ActionResult AnotherTaskWithDifferentRequirements() { }
I’d like to try this out next time I get back into ASP.NET MVC, the global.asax event technique felt a little too magical and I don’t think Uncle Bob would approve.
I’ve read several just right stuff here. Definitely price bookmarking for revisiting. I wonder how much effort you put to create such a magnificent informative web site.
I have been surfing online more than 3 hours today, yet
I never found any interesting article like yours. It is pretty worth enough for me.
Personally, if all website owners and bloggers made good content as you did, the web will be much more useful than ever before.