如何在不依赖NHibernate的情况下为每个请求实现NHibernate会话?

时间:2010-05-26 12:34:08

标签: asp.net-mvc nhibernate dependency-injection structuremap

我之前提出过这个问题,但我仍然在努力寻找一个可以让我理解的例子(请不要只是告诉我在没有至少一些指示的情况下查看S#arp架构项目)。< / p>

到目前为止,我已经在我的网络项目中实现了近乎持久的无知。我的存储库类(在我的数据项目中)在构造函数中使用了一个ISession:

public class ProductRepository : IProductRepository
{
    private ISession _session;
    public ProductRepository(ISession session) {
        _session = session;
    }

在我的global.asax中,我公开当前会话,并在beginrequest和endrequest上创建和处理会话(这是我对NHibernate的依赖):

    public static ISessionFactory SessionFactory = CreateSessionFactory();

    private static ISessionFactory CreateSessionFactory() {
        return new Configuration() 
            .Configure()
            .BuildSessionFactory();
    }

    protected MvcApplication()  {
        BeginRequest += delegate {
            CurrentSessionContext.Bind(SessionFactory.OpenSession());
        };
        EndRequest += delegate {
            CurrentSessionContext.Unbind(SessionFactory).Dispose();
        };
    }

最后我的StructureMap注册表:

    public AppRegistry() {
        For<ISession>().TheDefault
            .Is.ConstructedBy(x => MvcApplication.SessionFactory.GetCurrentSession());

        For<IProductRepository>().Use<ProductRepository>();
    }

似乎我需要我自己的ISession和ISessionFactory的通用实现,我可以在我的web项目中使用它并注入我的存储库?

所以只是为了澄清 - 我在我的存储库层使用NHibernate并希望使用session-per-(http)请求。因此,我正在向我的存储库构造函数中注入一个ISession(使用structuremap)。目前,为了在每个请求中创建和处理会话,我必须从我的web项目中引用NHibernate。这是我想删除的依赖项。

谢谢, 本

3 个答案:

答案 0 :(得分:3)

为什么不创建IHttpModule并在那里执行创建和处理(可能在Begin_Request和End_Request事件中),而是将IHttpModule放在具有NHibernate依赖项的项目中。例如

namespace MyWebApp.Repository.NHibernateImpl
{
    public class NHibernateModule : IHttpModule
    {
        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(Context_BeginRequest);
            context.EndRequest += new EventHandler(Context_EndRequest);
        }

        private void Context_BeginRequest(object sender, EventArgs e)
        {
            // Create your ISession
        }

        private void Context_EndRequest(object sender, EventArgs e)
        {
            // Close/Dispose your ISession
        }

        public void Dispose()
        {
            // Perhaps dispose of your ISessionFactory here
        }
    }
}

也许有更好的方法,我也有兴趣知道这一点,所以有其他建议吗?

答案 1 :(得分:2)

在我看来,你应该接受ISession并直接使用它。许多会话请求实现的问题是它们会延迟提交数据库更改,直到HTTP请求结束。如果事务失败,那么您在此处所能做的就是将用户引导到一般错误页面。在页面上管理事务要好得多,这样您就可以更有效地捕获和处理错误。如果采用这种方式,则需要访问ISession或包装器来控制事务。

此外,在某些时候,您的应用程序可能需要使用ISession公开的属性或方法,尤其是Merge和Load。

答案 2 :(得分:0)

感谢大家的帮助。更多的研究使我进入了NHibernate Burrow项目。

从项目常见问题解答(http://nhforge.org/wikis/burrow/faq.aspx):

Burrow是一个轻量级的中间件,用于支持使用NHibernate的.Net应用程序(在本文中也可称为NH)作为ORM框架。使用带有NHibernate的Asp.net可能是一个挑战,因为NHibernate是一个有状态的环境,而Asp.net是一个无状态框架。 Burrow可以通过提供先进的智能会话/事务管理和其他便利来帮助解决这一冲突。

我不得不跳过一些箍,让它在我的项目中运作。由于当前版本使用旧版本的NHibernate,我必须从主干下载latest source,在VS中打开,添加对最新版NHibernate的引用并重新编译(幸运的是没有错误)。

我以多种方式测试了NHibernate Burrow。

1)继续将ISession注入我的存储库

为此,我必须将对NHibernate,NHibernate.Burrow和NHibernate.Burrow.WebUtil的引用添加到我的MVC项目中。

在web.config中我必须设置Burrow(参见http://nhforge.org/wikis/burrow/get-started.aspx),然后在我的StructureMap注册表中添加以下内容:

       For<ISession>()
            .TheDefault.Is
            .ConstructedBy(x => new NHibernate.Burrow.BurrowFramework().GetSession());          

我喜欢这种方法,因为这意味着我的存储库(或控制器)不与Burrow耦合。我不太喜欢我必须在我的web项目中引用这三个程序集的事实,但至少我丢失了管理会话的代码 - 这全部由Burrow处理。

2)第二种方法是在我的存储库构造函数中设置ISession,如下所示:

    public ProductRepository() : 
        this(new BurrowFramework().GetSession()) { }

    public ProductRepository(ISession session) {
        _session = session;
    }

我仍然可以覆盖ISession,使我的存储库可测试。然后,我直接依赖于Burrow,但也许这不是一件坏事?

从好的方面来说,我需要从我的web项目中引用的唯一程序集是NHibernate.Burrow.WebUtils。

有兴趣看看两个人中哪一个会去,为什么。