记录层边界上的异常

时间:2009-03-11 14:10:07

标签: c# .net

在第196页的应用程序体系结构指南v2.0a中(或遵循此link),作者提到了此准则:

“设计适当的异常传播策略。例如,允许例外 冒泡到边界层,可以根据需要对其进行记录和转换 在将它们传递到下一层之前。“

在.NET(C#)中实现此目的的最佳方法是什么?

3 个答案:

答案 0 :(得分:1)

他说的是你没有捕捉到每个班级的错误。相反,你达到了边界条件。通常,如果您将此视为UI,并将Web服务(ASMX或WCF)包含为UI,则可以在这些层中进行捕获。

在Web应用程序中,唯一的边界可能是UI,因此您只能捕获网站本身的异常。

在分布式应用程序中,您可能具有服务边界(Web服务,如上所述)并且您可以在那里捕获。

你不想做的是让每个班级都在堆栈捕获,记录和抛出相同的异常,因为你最终会得到太多噪音和信号不足。

答案 1 :(得分:1)

我认为当他们谈论层边界时,他们谈论的是安全敏感度发生变化或呼叫来自您的影响范围之外的地方。主要担心的是,在例外情况下,安全敏感信息不会泄露出您的应用程序。因此,例如,如果错误是针对数据库连接,则异常消息可能是“无法访问服务器ServerName上的数据库”。如果这种异常从您的应用程序中消失,它会给黑客提供数据库服务器的名称,这是一件坏事。

这些安全边界通常位于流程边界。在服务器应用程序上,这意味着任何公共Web服务,远程过程调用或那种事情。此外,在Web和Win-Forms应用程序中,还有处理任何未处理异常的全局错误处理程序。我不希望进程中的dll包含这样的边界。

一旦确定了每个边界入口点,就应该使用try catch,然后将异常传递给Microsoft Exception Handling Block。异常处理块允许记录异常,并允许您决定向用户抛出哪些异常详细信息。这有助于确保安全敏感信息不会在异常堆栈跟踪中泄漏出应用程序。

WinForms中的全局异常处理程序:

在WinForms中,有两个全局异常处理程序,它们被定义为在出现未处理异常时触发的事件。最好的办法是在Application.Run语句之前在main()函数中绑定它们,如下所示:

    static void Main()
    {
        AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
        Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);

        Application.Run(new Form1());
    }

使用异常应用程序块,您可以像这样处理这些事件:

    using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;

    // ...

    static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
    {
        bool rethrow = ExceptionPolicy.HandleException(e.Exception, "Thread Policy");
        if (rethrow)
        {
            Application.Exit();
        }
    }

    static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        ExceptionPolicy.HandleException((Exception)e.ExceptionObject, "App Policy");
        // This event always exits the 
        // application so there is no point in looking at 
        // HanleException result.
    }

这两个事件之间的区别在于ThreadException事件只处理由WinForm的线程创建的事件。如果您不在事件中重新抛出异常,它还将允许应用程序继续。 UnhandledException事件将捕获进程中的所有异常,但不允许您继续,因此它仅适用于日志记录。

最后要使MS Exception块工作,你需要在App.Config文件中添加一些配置,如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="exceptionHandling" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=2.0.0.0, Culture=neutral, PublicKeyToken=e99c4c62013e92da"/>    
  </configSections>

  <exceptionHandling>
    <exceptionPolicies>
      <add name="App Policy">
        <exceptionTypes>
          <add name="App Exception" type="System.Exception, mscorlib" postHandlingAction="None" />
        </exceptionTypes>
      </add>
      <add name="Thread Policy">
        <exceptionTypes>
          <add name="App Exception" type="System.Exception, mscorlib" postHandlingAction="None" />
        </exceptionTypes>
      </add>
    </exceptionPolicies>
  </exceptionHandling>
</configuration>

你通常会做一个比这更复杂的例外政策,但我不会在这里讨论。

ASP.Net中的全局异常处理程序

在ASP.Net中,事情变得容易一些。您需要做的就是在Global.asax文件中实现Application_Error事件。要获取最后一个错误,请调用Server.GetLastError()并继续,而不必重新抛出异常调用Server.ClearError()。所以你的代码看起来像这样:

<%@ Application Language="C#" %>
<script runat="server">        
    void Application_Error(object sender, EventArgs e) 
    {
        Exception ex = Server.GetLastError();
        bool rethrow = ExceptionPolicy.HandleException(ex, "App Exception");
        if (!rethrow)
        {
            Server.ClearError();
        }
        Response.StatusCode = 500;
    }       
</script>

答案 2 :(得分:0)

你的意思是,除了try / catch?

层边界的概念在C#中没有表示。您必须设计代码,以便可以看到图层边界,然后在这些边界放置适当的try / catch块。

企业库中的异常处理应用程序块对此很有用,因为它允许您配置如何包装异常。