Ninject中的OnePerRequestModule导致在EndRequest上打开新的NHibernate会话

时间:2010-12-17 06:32:59

标签: nhibernate asp.net-mvc-2 ninject

更新

我接受了我的回答,因为我相信OnePerRequest模块不应该清除缓存,直到所有其他模块都有机会运行。但是,在我们将其余页面移植到MVC之后,我将重新设计我们的工作单元实现,以更符合Remo的建议。

我刚刚从Ninject 2.0升级到Ninject 2.1,我现在遇到了NHibernate UnitOfWork实现的问题。

我的实施如下。我有一个订阅BeginRequest和EndRequest的HttpModule,并且有以下代码。

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();
}

IRepository实现将NHibernate ISession作为依赖项。这是两个绑定。

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

NHibernate存储库在BeginRequest中打开一个事务并在EndRequest中提交它。随着升级到Ninject 2.1。 OnePerRequestModule现在正在干扰此代码。因为它首先附加到EndRequest事件,所以它在我的DataModule之前触发并从内核缓存中清除ISession。这意味着IRepository获得了一个全新的ISession,因此无法提交事务。使事情变得复杂的是,OnePerRequestModule不是一次向内核注册,而是两次注册。一次进入KernelBase构造函数,再次进入NinjectHttpApplication中的Application_Start方法。

所以它非常令人费解,我发现关闭此功能的方法之一是致电OnePerRequestModule.StopManaging(Kernel); 在Global.asax.cs中的OnApplicationStarted方法中使用两次。有没有人对如何处理这个有任何建议?我假设有一个原因引入了OnePerRequestModule,但是继续我的UnitOfWork实现会很好。

3 个答案:

答案 0 :(得分:0)

我认为这不是一个好的实施。您应该在激活操作中调用BeginRequest,在存放库中调用CloseRequest。这样你就没有服务定位器,比如在内核上调用get。

答案 1 :(得分:0)

我已经重写了我的UnitOfWork实现,因为我们已经将我们的WebForms应用程序重写为MVC。我现在有一个FilterAttribute,它应用于每个数据封装的动作,如下所示:

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 :(得分:-2)

我决定编辑Ninject.Web.Mvc项目来解决这个问题。在NinjectHttpApplication类中。我已将此语句this.onePerRequestModule.Init(this);从构造函数移动到Init方法。这可确保onePerRequestModule最后注册其事件处理程序。