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

Gui*_*ais 11 nhibernate asp.net-mvc 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.以这个页面为例,我认为这很有希望,但仍需要控制器级别的过滤器.
  • 使用HttpContext.Current.Items存储请求会话.这与Global.asax.cs中的几行代码相结合,可以轻松地为我提供请求级别的会话.但是,这意味着将在NHibernate和我的视图(HttpContext)之间注入依赖项.

非常感谢你!

Gui*_*ais 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");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

在Global.asax.cs中:

protected void Application_EndRequest(object sender, EventArgs args)
{
    NHibernateSessionManager.CloseSession();
}
Run Code Online (Sandbox Code Playgroud)

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