当UnitOfWork是整个请求时,如何最好地通知用户NHibernate异常?

时间:2009-04-13 23:23:01

标签: asp.net nhibernate error-handling

我目前正在ASP.NET WebForms应用程序中使用View模式中的Open Session(从Billy McCafferty的http://www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx改编而来)。要简单说明这里发生的事情:

  1. 在请求开始时打开NHibernate事务
  2. 请求结束时提交(回滚任何错误)
  3. 我通常通过在Application_Error(我记录,重定向到通用错误页面等)中捕获它们来处理任何异常数据库错误,如下所示:

            ...
              if (Context != null && Context.IsCustomErrorEnabled)
            {
                Server.Transfer(ErrorPageLocation, false);
            }
            else
            {
                log.Error("Unhandled Exception trapped in Global.asax", exception);
            }
    

    但是对于NHibernate,当我遇到任何NHibernate / Database错误时,在我的常规Server.Transfer(显然没有在请求的后期发生转移)错误重定向的请求中为时已晚(尽管日志记录仍然发生)。作为一个非常快速的解决方案,我在我的自定义HttpModule的HttpApplication Context EndRequest中完成了以下操作:

            try
            {
                // Commits any open transaction and throws after rolling back any HibernateException and closing session.
                NHibernateSessionManager.Instance.CommitTransaction();
            }
            catch (HibernateException)
            {
                HttpContext.Current.Response.Redirect(ERROR_PAGE_LOCATION);
            }
            finally
            {
    
                NHibernateSessionManager.Instance.CloseSession();
            }
    

    ...但这闻起来不仅仅是因为我现在在网络中引用了NHibernate,而且主要是因为我确信必须有更好的方法。在数据库/ NHibernate错误的情况下处理将用户重定向到通用错误页面的更好方法是什么,因为此时抛出的任何异常都会在进程中被抛出太晚而无法在请求中进一步处理使用Global.asax.cs Application_Error中的Server.Transfer?更进一步,使用Web服务它变得更加棘手,因为上面的hack显然没有效果(并且在接收端没有异常被抛出 - 在我的情况下,最常见的是在客户端ajax调用中)。 / p>

    请告诉我,我错过了一些明显的东西(通常在我点击提交这些问题后,很明显就会发生这种情况)!

3 个答案:

答案 0 :(得分:2)

据我所知,视图模式中的开放会话并不一定意味着整个请求的工作单元是开放的。我通过在我的控制器方法中明确定义一个工作单元来处理这个(在ASP.NET MVC中,而不是webforms,但原理是相同的)。在控制器方法返回任何数据库事务之前,我可以在此时正确处理任何数据更新错误。即使在事务已提交之后,会话仍保持打开状态。就我的目的而言,视图中的开放会话主要用于允许在视图阶段中延迟加载相关对象。我选择这样做有两个主要原因:

  1. 我不希望在将视图呈现给响应时保持打开任何数据库事务 - 这不是必需的,并且对于数据库事务,越短越好。
  2. 使用“使用”模式,拥有明确的工作单元并不需要额外的努力
  3. 在视图阶段发生的任何NHibernate错误对我来说都不太重要 - 事务和任何更新已经完成,所以我可以处理那些具有通用的catch-all重定向错误处理程序。

答案 1 :(得分:0)

我们在错误页面非常基本的地方做的一件事就是简单地干预Page.OnError(通过基页)并通过Response发出html。有点蹩脚,但在集中的位置获得所需的结果。

答案 2 :(得分:0)

也许您可以在global.asax中声明一个bool,以指示上一个请求中发生了错误。您可以在Application_Error中将其设置为true,然后在Application_BeginRequest中检查其值并重定向是否为真?