2014-02-12 71 views
0

这是我今天遇到的另一个奇怪的问题!我创建了使用nhibernate的MVC 4应用程序。并在我的HomeController上添加了名为[LoggingNHibernateSessionAttribute]的过滤器属性,该属性管理每个操作的会话。我遵循'ASP.NET MVC4和Apress发布的Web API'。NHibernate会话关闭时,页面

public class LoggingNHibernateSessionAttribute : ActionFilterAttribute 
{ 
    private readonly IActionLogHelper _actionLogHelper; 
    private readonly IActionExceptionHandler _actionExceptionHandler; 
    private readonly IActionTransactionHelper _actionTransactionHelper; 

    public LoggingNHibernateSessionAttribute() 
     : this(WebContainerManager.Get<IActionLogHelper>(), 
     WebContainerManager.Get<IActionExceptionHandler>(), 
     WebContainerManager.Get<IActionTransactionHelper>()) 
    { 
    } 

    public LoggingNHibernateSessionAttribute(
     IActionLogHelper actionLogHelper, 
     IActionExceptionHandler actionExceptionHandler, 
     IActionTransactionHelper actionTransactionHelper) 
    { 
     _actionLogHelper = actionLogHelper; 
     _actionExceptionHandler = actionExceptionHandler; 
     _actionTransactionHelper = actionTransactionHelper; 
    } 

    public override void OnActionExecuting(ActionExecutingContext actionExectingContext) 
    { 
     _actionLogHelper.LogEntry(actionExectingContext.ActionDescriptor); 
     _actionTransactionHelper.BeginTransaction(); 
    } 

    public override void OnActionExecuted(ActionExecutedContext actionExecutedContext) 
    { 
     _actionTransactionHelper.EndTransaction(actionExecutedContext); 
     _actionTransactionHelper.CloseSession(); 
     _actionExceptionHandler.HandleException(actionExecutedContext); 
     _actionLogHelper.LogExit(actionExecutedContext.ActionDescriptor); 
    } 
} 

ActionTransactionHelper

public class ActionTransactionHelper : IActionTransactionHelper 
{ 
    private readonly ISessionFactory _sessionFactory; 
    private readonly ICurrentSessionContextAdapter _currentSessionContextAdapter; 

    public ActionTransactionHelper(
     ISessionFactory sessionFactory, 
     ICurrentSessionContextAdapter currentSessionContextAdapter) 
    { 
     _sessionFactory = sessionFactory; 
     _currentSessionContextAdapter = currentSessionContextAdapter; 
    } 

    public void BeginTransaction() 
    { 
     var session = _sessionFactory.GetCurrentSession(); 
     if (session != null) 
     { 
      session.BeginTransaction(); 
     } 
    } 

    public bool TransactionHandled { get; private set; } 

    public void EndTransaction(ActionExecutedContext filterContext) 
    { 
     var session = _sessionFactory.GetCurrentSession(); 

     if (session == null) return; 
     if (!session.Transaction.IsActive) return; 

     if (filterContext.Exception == null) 
     { 
      session.Flush(); 
      session.Transaction.Commit(); 
     } 
     else 
     { 
      session.Transaction.Rollback(); 
     } 

     TransactionHandled = true; 
    } 

    public bool SessionClosed { get; private set; } 

    public void CloseSession() 
    { 
     if (_currentSessionContextAdapter.HasBind(_sessionFactory)) 
     { 
      var session = _sessionFactory.GetCurrentSession(); 
      session.Close(); 
      session.Dispose(); 
      _currentSessionContextAdapter.Unbind(_sessionFactory); 

      SessionClosed = true; 
     } 
    } 
} 

运行应用程序时,我可以在数据库中保存的实体。但是当我点击刷新按钮和异常抛出指示会话关闭。

我不知道为什么会发生这种情况。 (我搜索并找到这个NHibernate throwing Session is closed,但无法解决我的问题)。

在我的NinjectConfigurator中,我将inRequestScope()添加到所有注入但没有答案。我检查了什么时候刷新页面会话将被打开。但我不知道它为什么说会议闭幕?!

UPDATE:

当我第一次运行该应用程序。我可以创建一个新成员。但是当我点击刷新按钮时,会话将意外关闭! 第一次运行:

  1. 一切击中刷新按钮后,效果很好

  1. 一个新的会话绑定到当前上下文。
  2. 新的会话将被注入该库(会话是打开的)
  3. 的ActionTransactionHelper调用的BeginTransaction() 4- customMembership的createUser(....)称为 5但当_userRepositoy.save(用户)称为在存储库会话关闭!!!!

注意:但是当仍然没有调用endTransaction和closeSession时。但会议如何关闭?如果我在onActionExecute()中注释closeSession(),则返回 。会话一直开放,如果刷新页面,一切都会很好。 我查了很多,并尝试了我认识的不同方式。它只发生在我第二次想用我的customMembership进行CRUD操作时。

对于其他实体,它的作用就像一个魅力! enter image description here 我已经上传了我的示例代码。用于测试只需创建并清空数据库并更改连接字符串。然后去到localhost:*****/API /类别(用户,并通过不要求)

下载示例项目: 大小:47 MB​​ https://www.dropbox.com/s/o63wjng5f799fii/Hashem-MVC4ServicesBook.rar

大小:54 MB Zip格式: https://www.dropbox.com/s/smrsbz4cbtznx1y/Hashem-MVC4ServicesBook2.zip

回答

1

这里非常重要的一点,可能是NHibernate的本质。 NHibernate和它的Session在ASP.NET MVC中活得更长,然后可以预料。我指的不仅是内部的

  • ActionExecuting的(控制器操作开始)
  • ActionExecuted(查看或重定向的叫法),其实

会议还必须度过渲染的阶段。因为我们可以在“Action()”中加载一些代理,但是它的集合只能在View渲染期间加载lazily。因此,即使在这些阶段Session必须(从请求begining同一个Session)打开

  • ResultExecuting(代理可能一开始就被这里只加载)
  • ResultExecuted(几乎全部完成,让我们紧密会话)

其他的话...... 保持会话打开throught完整的请求。从授权直到呈现内容。

注:Anohter提示,只是为了确保一切正常,我使用的这个场景(也许你做的一样好)

  1. 客户端形式是约将数据发送到服务器。该方法是POST,该行动是更新()
  2. 发送FORM即将服务器,操作更新()是triggerred - 所有交易的东西到位(如上所述)
  3. 一旦NHibernate的持续数据到数据库,更新()动作结束,被重定向到行动
    • Detail()如果一切正常或
    • Edit(),如果出现错误
  4. 用户的浏览器重定向到操作细节或编辑。因此,如果用户进行刷新,则刷新细节或编辑。该Update()根本没有被调用(这是一个POST方法)

事实上,步骤1.是操作DetailEdit之一。在这种情况下,我们将面临这个问题...

+0

上传的示例代码。请检查。 –

0

你有这个错误,因为Asp.Net MVC不会创建LoggingNHibernateSessionAttribute每个请求的新实例。它首次请求操作并在将来使用此实例时会创建一个新实例。

行为如下:

  1. Post首先调用 - 创建>一个又一个的 'LoggingNHibernateSession' 实例
  2. - 创建
  3. Put首先调用 'LoggingNHibernateSession'>新实例
  4. 第二次调用Put - >使用上一步中的“LoggingNHibernateSession”实例
  5. 第一次调用Delete - >另一个 'LoggingNHibernateSession' 的实例使用Func<IActionLogHelper>代替在构造IActionLogHelper创建

    [LoggingNHibernateSession] 
    public JsonResult Post(Dto data) 
    { 
        /* ... */ 
    } 
    
    [LoggingNHibernateSession] 
    public JsonResult Put(int id, Dto data) 
    { 
        /* ... */ 
    } 
    
    [LoggingNHibernateSession] 
    public JsonResult Delete(int id) 
    { 
        /* ... */ 
    } 
    

它可以解决。IActionLogHelper的实例可以在OnActionExecuting方法中初始化。

public class LoggingNHibernateSessionAttribute : ActionFilterAttribute 
{ 
    /* your code */ 
    private readonly Func<IActionTransactionHelper> _getActionTransactionHelper; 
    private IActionTransactionHelper _actionTransactionHelper; 

    public LoggingNHibernateSessionAttribute() 
     : this(WebContainerManager.Get<IActionLogHelper>(), 
     WebContainerManager.Get<IActionExceptionHandler>(), 
     () => WebContainerManager.Get<IActionTransactionHelper>()) 
    { 
    } 

    public LoggingNHibernateSessionAttribute(
     IActionLogHelper actionLogHelper, 
     IActionExceptionHandler actionExceptionHandler, 
     Func<IActionTransactionHelper> getActionTransactionHelper) 
    { 
     _actionLogHelper = actionLogHelper; 
     _actionExceptionHandler = actionExceptionHandler; 
     _getActionTransactionHelper = getActionTransactionHelper; 
     _actionTransactionHelper = null; 
    } 

    public override void OnActionExecuting(ActionExecutingContext actionExectingContext) 
    { 
     _actionTransactionHelper = _getActionTransactionHelper(); 
     _actionLogHelper.LogEntry(actionExectingContext.ActionDescriptor); 
     _actionTransactionHelper.BeginTransaction(); 
    } 

    /* your code */ 
} 
+0

我想可能是因为这个。你会解释更多关于你的解决方案吗? –

+0

通常IoC容器的实例是在'Application_Start'中创建的,并放置在'Application_End'中。所以,你可以创建一个函数来解析每次调用时的依赖(它类似于延迟加载),并且每次请求(OnActionExecuting)都会返回一个新的IActionTransactionHelper实例。上传的示例代码为 –

+0

。请检查。 –