代码之家  ›  专栏  ›  技术社区  ›  Ted

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

  •  1
  • Ted  · 技术社区  · 17 年前

    我目前正在ASP.NETWebForms应用程序中使用视图中的开放会话模式(改编自Billy McCafferty的) http://www.codeproject.com/KB/architecture/NHibernateBestPractices.aspx ).要说明此处发生的情况:

    1. 在请求开始时打开NHibernate事务
    2. 在请求结束时提交(回滚任何错误)

    我通常通过在Application_Error(我在其中记录、重定向到通用错误页面等)中捕获异常数据库错误来处理任何异常数据库错误,如下所示:

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

    但是对于NHibernate,当我遇到任何NHibernate/数据库错误时,在请求中执行常规服务器操作已经太迟了。传输(显然不会在请求中这么晚发生传输)错误重定向(尽管仍会进行日志记录)。作为一个非常快速的修复,我在自定义HttpModule的HttpApplication上下文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错误时,如果此时抛出的任何异常在处理过程中太晚而无法在服务器的请求中得到进一步处理,那么有什么更好的方法来处理将用户重定向到通用错误页。Transfer in Global.asax.cs Application_错误?更进一步说,对于web服务,它变得更加棘手,因为上述攻击显然没有任何效果(并且没有异常被抛出到接收端进行处理——在我的例子中,最典型的是在客户端ajax调用中)。

    请告诉我,我遗漏了一些明显的东西(通常在我点击提交这些问题之后,这些明显的东西会立即击中我)!

    3 回复  |  直到 17 年前
        1
  •  2
  •   Steve Willcock    17 年前

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

    1. 当视图呈现给响应时,我不想让任何数据库事务保持打开状态——这是不必要的,对于数据库事务,越短越好。
    2. 对于“使用”模式,拥有一个明确的工作单元并不需要太多额外的努力

        2
  •  0
  •   Adam Fyles    17 年前

    在错误页面非常基本的情况下,我们所做的一件事就是简单地干预page.OnError(通过一个基本页面)并通过响应发出html。虽然有点蹩脚,但可以在集中的位置获得所需的结果。

        3
  •  0
  •   Jamie Ide    17 年前

    也许您可以在global.asax中声明一个bool,以指示上一个请求中发生了错误。你会把它设置为真的 Application_Error ,然后将其值签入 Application_BeginRequest