如何在我的项目中实现强大的每个请求会话模式,同时专注于信息隐藏?

时间:2010-01-12 01:51:27

标签: asp.net-mvc nhibernate session information-hiding

我目前正在构建一个ASP.NET MVC项目,NHibernate作为其持久层。

目前,已经实现了一些功能,但只使用本地NHibernate会话:访问数据库(读取或写入)的每个方法都需要使用“using()”子句实例化自己的NHibernate会话。

问题在于我想利用NHibernate的延迟加载功能来提高项目的性能。

这意味着每个请求都会打开一个NHibernate会话,直到呈现视图为止。此外,必须支持同时请求(同时多个会话)。

如何尽可能干净地实现这一目标?

我在网上搜索了一下,了解了每个请求的会话模式。我看到的大多数实现使用某种Http *(HttpContext等)对象来存储会话。此外,使用Application_BeginRequest / Application_EndRequest函数很复杂,因为当我只想为每个请求实例化一次会话时,它们会被触发每个HTTP请求(aspx文件,css文件,js文件等)。

我担心的是我不希望我的视图或控制器能够访问NHibernate会话(或者更常见的是NHibernate命名空间和代码)。这意味着我不想在控制器级别处理会话,也不想在视图处理会话。

我有几个选择。哪一个看起来最好?

  • 使用在控制器操作之前和之后触发的拦截器(如GRAILS)。这些将打开和关闭会话/交易。这是否可以在ASP.NET MVC世界中使用?
  • 在Web上下文中使用NHibernate提供的CurrentSessionContext Singleton。以this page为例,我认为这很有希望,但仍需要控制器级别的过滤器。
  • 使用HttpContext.Current.Items存储请求会话。这与Global.asax.cs中的几行代码相结合,可以轻松地为我提供请求级别的会话。但是,这意味着将在NHibernate和我的视图(HttpContext)之间注入依赖关系。

非常感谢!

5 个答案:

答案 0 :(得分:13)

好吧,经过几天的工作,我终于决定使用HttpContext.Current.Items来加载会话。

效果很好!

我是这样做的

import System.Web
class SessionManager {
    public static ISession GetSession()
        var session = HttpContext.Current.Items["NHibernateSession"];
        if (session == null) {
            session = ...; // Create session, like SessionFactory.createSession()...
            HttpContext.Current.Items.Add("NHibernateSession", session);
        }
        return session;
    }

    public static void CloseSession()
    {
        var session = HttpContext.Current.Items["NHibernateSession"];
        if (session != null) {
            if (session.IsOpen) {
                session.close();
            }
            HttpContext.Current.Items.Remove("NHibernateSession");
        }
    }
}

通过使用此类提供的静态方法,可以获得与当前HttpContext(当前Web请求)绑定的会话(例如,在Controller中)。我们需要另一段代码来在请求完成时调用CloseSession()方法。

在Global.asax.cs中:

protected void Application_EndRequest(object sender, EventArgs args)
{
    NHibernateSessionManager.CloseSession();
}

会话完成后会自动调用Application_EndRequest事件,因此可以正确关闭会话并将其处理掉。这很有用,因为否则我们必须在每个Controller中执行此操作!

答案 1 :(得分:2)

将DI与IoC一起使用。大多数IoC都带有每请求实例化行为。

答案 2 :(得分:2)

我的“解决方案”涉及使用Unity在控制器中为每个请求注入会话:

http://letsfollowtheyellowbrickroad.blogspot.com/2010/05/nhibernate-sessions-in-aspnet-mvc.html

答案 3 :(得分:1)

看看S#arp Architecture。对于ASP.NET MVC和NHibernate来说,这是一个非常好的架构。

答案 4 :(得分:1)

您可以添加一个可以管理您的NHibernate会话的动作过滤器。交易。 (这可以在动作或控制器级别完成。)以下是一个示例:

http://weblogs.asp.net/srkirkland/archive/2009/09/03/asp-net-mvc-transaction-attribute-using-nhibernate.aspx