0
votes

UPDATE

I've accepted my answer since I believe that the OnePerRequest module shouldn't clear out the cache until all other modules have had a chance to run. However, after we port the rest of our pages to MVC I will be reworking our Unit of Work implementation to be more in line with Remo's suggestion.

I just upgraded from Ninject 2.0 to Ninject 2.1 and I'm now having issues with my NHibernate UnitOfWork implementation.

My implementation is as follows. I have an HttpModule that subscribes to BeginRequest and EndRequest and has the following code.

public void BeginRequest(object sender, EventArgs e)
{
 var app = (WebApplication)sender;
 var repository = app.Kernel.Get<IRepository>();

 repository.BeginRequest();
}

public void EndRequest(object sender, EventArgs e)
{
 var app = (WebApplication)sender;
 var repository = app.Kernel.Get<IRepository>();

 repository.EndRequest();
}

The IRepository implementation takes an NHibernate ISession as a dependency. Here are the two bindings.

Bind<ISession>().ToMethod(context => NHibernateSessionFactory.Instance.OpenSession()).InRequestScope();
Bind<IRepository>().To<NHibernateRepository>().InTransientScope();

NHibernate repository opens up a transaction in BeginRequest and commits it in EndRequest. With the upgrade to Ninject 2.1. The OnePerRequestModule is now interfering with this code. Since it is attached to the EndRequest event first it fires before my DataModule and clears the ISession from the Kernel cache. This means that the IRepository gets a brand new ISession and thus can't commit the transaction. Complicating matters is the fact that OnePerRequestModule registers with the Kernel not once, but twice. Once in the KernelBase constructor and once again in the Application_Start method in the NinjectHttpApplication.

So it's pretty convoluted and one of the ways I've found to turn this functionality off is to call OnePerRequestModule.StopManaging(Kernel); twice in the OnApplicationStarted method in my Global.asax.cs. Does anyone have any suggestions in regards to how to handle this? I'm assuming there's a reason OnePerRequestModule was introduced, but it would be nice to keep with my UnitOfWork implementation.

3

3 Answers

0
votes

I think that's not a good implementation. You should rather call BeginRequest in a activation action and CloseRequest in the dispose of the repository. That way you do not have thes too service locator like get calls on the kernel.

0
votes

I've rewritten my UnitOfWork implementation as we have rewritten our WebForms app to MVC. I now have a FilterAttribute that is applied to every data encapsulated action that looks like this:

public class UnitOfWorkAttribute : FilterAttribute, IActionFilter
{
    [Inject]
    public IUnitOfWork UnitOfWork { get; set; }

    public UnitOfWorkAttribute()
    {
        Order = 0;
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        UnitOfWork.Begin();
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        UnitOfWork.End();
    }
}
-2
votes

I've decided to edit the Ninject.Web.Mvc project to fix this. In the NinjectHttpApplication class. I've moved this statement this.onePerRequestModule.Init(this); from the constructor to the Init method. This ensures that the onePerRequestModule registers its event handler last.