2014-02-12 63 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

。請檢查。 –