Asp.net-Mvc

發生異常後不要刷新會話 - NHibernate

  • April 6, 2016

我正在.NET 3.5、NHibernate 下開發一個 ASP.NET MVC Web 應用程序並託管在 Windows Azure 上。當 web 應用程序從本地開發結構執行時,它可以正常工作。然而,當我將它移動到 Windows Azure 時,從 MVC Web 角色執行的每個插入都以下面列出的異常結束。

知道我的 NHibernate 邏輯有什麼問題嗎?(可能是會話管理,不確定)

$$ AssertionFailure: null id in Lokad.Translate.Entities.User entry (don’t flush the Session after an exception occurs) $$ NHibernate.Event.Default.DefaultFlushEntityEventListener.CheckId(Object obj, IEntityPersister persister, Object id, EntityMode entityMode) +292 NHibernate.Event.Default.DefaultFlushEntityEventListener.GetValues(Object entity, EntityEntry entry, EntityMode entityMode, Boolean mightBeDirty, ISessionImplementor session) + 93 NHibernate.Event.Default.DefaultFlushEntityEventListener.OnFlushEntity(FlushEntityEvent 事件)+158 NHibernate.Event.Default.AbstractFlushingEventListener.FlushEntities(FlushEvent 事件)+469 NHibernate.Event.Default.AbstractFlushingEventListener.FlushEverythingToExecutions(FlushEvent 事件)+339 NHibernate.Event。 Default.DefaultFlushEventListener.OnFlush(FlushEvent 事件) +85 NHibernate.Impl.SessionImpl.Flush() +275 NHibernate.Transaction.AdoTransaction.Commit() +236 Lokad.Translate。Repositories.PageRepository.Create(Page page) Lokad.Translate.Controllers.PagesController.Create(Page page) lambda_method(ExecutionScope , ControllerBase , Object$$ $$) +69 System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary 2 parameters) +251 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary2 參數) +31 System.Web.Mvc.<>c__DisplayClassa.b__7() +88 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter 過濾器, ActionExecutingContext preContext, Func1 continuation) +534 System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList1 個過濾器,ActionDescriptor actionDescriptor,IDictionary`2 參數)+312 System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +856 System.Web.Mvc.Controller.ExecuteCore() +185 System.Web.Mvc。 MvcHandler.ProcessRequest(HttpContextBase httpContext) +221 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +586 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +177

請注意,我正在使用_session.FlushMode = FlushMode.Commit;並且User在自定義中使用RoleProvider

public class SimpleRoleProvider : RoleProvider 
{
   readonly UserRepository Users = new UserRepository();

   public override string[] GetRolesForUser(string username)
   {
       try
       {
           var user = Users.Get(username);

           // no role if user is not registered
           if (null == user) return new string[0];

           // default role for registered user
           return user.IsManager ? new[] { "Manager", "User" } : new[] { "User" };
       }
       catch (Exception)
       {
           // role should not fail in case of DB issue.
           return new string[0];
       }
   }
}

我終於找到了解決我自己問題的方法。如果人們有興趣,我會在此處發布解決方案。

public class SimpleRoleProvider : RoleProvider 
{
   // isolated session management for the RoleProvider to avoid
   // issues with automated management of session lifecycle.

   public override string[] GetRolesForUser(string username)
   {
       using (var session = GlobalSetup.SessionFactory.OpenSession())
       {
           var users = new UserRepository(session);
           var user = users.Get(username);

           // no role if user is not registered
           if (null == user) return new string[0];

           // default role for registered user
           return user.IsManager ? new[] {"Manager", "User"} : new[] {"User"};
       }
   }
}

基本上發生的事情是RoleProvider儲存庫似乎沒有與正常的視圖/控制器儲存庫相同的生命週期。結果,在呼叫 RoleProvider 時,NHibernate 會話已經被釋放,導致上面觀察到的異常。

我已將程式碼替換為上面的以下程式碼。這個有自己的 NHibernate 會話管理,並最終工作正常。

您不應該在 NHibernate 事務期間擷取異常並忽略它們。

我試圖解釋為什麼。

例如,可能存在由數據庫中的約束引起的異常。(它也可能是由映射問題、屬性拋出的異常或其他任何原因引起的。) NHibernate 嘗試將記憶體中的狀態與數據庫同步。這是在送出時完成的 - 有時在查詢之前完成,以確保查詢是在實際數據上完成的。當同步失敗時,數據庫中的狀態是隨機的,一些變化是持久的,有些則不是。在這種情況下,您唯一能做的就是關閉會話。

考慮到程式碼中的決策和計算基於記憶體中的值。但是 - 在被忽略的異常的情況下,這個值不是數據庫中的值,它們永遠不會存在。因此,您的邏輯將決定併計算“幻想數據”。

順便說一句,擷取任何異常(無類型)並忽略它們絕不是一個好主意。您應該始終知道您處理的異常,並確保您可以繼續。

你在這裡做的是吞下程式錯誤。相信我,系統不會更穩定。問題只是:您是否注意到錯誤發生時,或者您是否在那裡忽略它,甚至將錯誤的結果保存到數據庫中?當您執行後者時,當您嘗試從數據庫中獲取數據時,當您的數據庫不一致以及出現其他錯誤時,您不必感到驚訝。而且您永遠不會找到導致錯誤的實際原因的程式碼。

引用自:https://stackoverflow.com/questions/1819034