























本文档维护在:http://wiki.entlib.net.cn/EntlibHelp31ExceptionHandlingApplicationBlock.ashx。
此主题描述了开发人员在处理异常时必须解决的绝大多数常见情况。每个场景解释了任务、描述了任务可能发生的真实世界情况,还包括了示范了如何使用异常处理应用程序块完成任务的代码。场景如下:
在异常处理过程中发生的异常
异 常可以发生在使用异常处理应用程序块进行异常处理时。这些异常通常是因为应用程序代码指定的异常处理策略不是应用程序配置的一部分,或者定制的异常处理程 序中有错误的代码。异常还可以发生在配置信息不可用的时候(例如,它没有包含有效的 XML )。因为异常可能包含敏感信息,应用程序块不会返回原始异常给应用程序,而是抛出一个新的异常。
如果应用程序配置信息无效,应用程序块会抛出 System.Configuration.ConfigurationErrorsException 类型的异常。在此异常抛出前,不会记录任何信息。
如果配置文件是有效的,应用程序块抛出 ExceptionHandlingException 类型的异常。应用程序块使用度量设置来决定原始的异常信息是否被记录日志。如果度量是可用的,应用程序块在抛出新的异常前在应用程序事件日志中记录原始异常信息。
经常需要的异常处理任务是记录与异常关联的信息为日志。异常处理应用程序块,与日志应用程序块联合,让你在配置文件中指定的地方记录格式化的异常信息。例如,客户应用程序通常在事件日志中记录应用程序信息,而电子商务应用程序的服务器组件可能在数据库中记录异常日志。
典型目标
要在任何其他异常处理发生前记录发生在应用程序层某层中的异常。应用程序中有类似于下列代码的代码在它的 catch 块中。
注意:代码不包含 FormatException 和 Logger.Log 方法。这些方法表示了创建格式化异常消息并将它写入日志目的地的典型应用程序代码。
C#
catch(SomeException e)
{
string formattedInfo = FormatException(e);
Logger.Log(e);throw e;
}
Visual Basic
Catch e As SomeException
Dim formattedInfo As String = FormatException(e)
Logger.Log(e)Throw e
End Try
解决方案
指派日志处理程序为策略的异常处理链中的第一个处理程序。异常处理应用程序块包含日志处理程序。
快速入门
关于如何记录异常日志的扩展示例,请参见快速入门漫游,漫游:记录异常日志。
使用日志处理程序
要使用日志处理程序,必须配置应用程序异常策略和日志应用程序块。必须修改应用程序以使用适当的异常处理策略。
配置应用程序异常策略
配置日志应用程序块
修改应用程序
修改应用程序代码以在异常发生时执行新的策略。下面的代码示范了如何来做这件事。候选的名称 “Logging Policy” 使用的是策略的名称。
C#
try
{
// Run code.
}
catch(Exception ex)
{
bool rethrow = ExceptionPolicy.HandleException(ex, "Logging Policy");
if (rethrow)
throw;
}
Visual Basic
Try
' Run code.
Catch ex As Exception
Dim rethrow As Boolean = ExceptionPolicy.HandleException(ex, "Logging Policy")
If (rethrow) Then
Throw
End If
End Try
使用提示
在配置应用程序块以使用日志处理程序时,请参考下面的信息。
经常需要的异常处理任务是用另一个异常替换原始异常。例如,如果异常要穿越信任边界,而你不想发送原始的异常,因为它包含了敏感信息。
典型目标
要用另一个更合适的异常替换包含敏感或者不需要的信息的原始异常,在应用程序的 catch 块中的代码类似于下面的代码。
C#
catch(SomeException e)
{
CustomException myException = new CustomException("Unable to access the configured data source");throw myException;
}
Visual Basic
Catch e As SomeException
Dim myException As CustomException = New CustomException("Unable to access the configured data source")Throw myException
End Try
解决方案
在异常处理链中使用替换处理程序。在传播异常到应用程序层外之前执行策略。
快速入门
如何使用异常处理应用程序块替换异常的扩展示例,请参见快速入门漫游,漫游:用另一个异常替换一个异常。
使用替换处理程序
下面的过程描述了如何使用替换处理程序。
使用替换处理程序
C#
try
{
// Run code.
}
catch(Exception ex)
{
bool rethrow = ExceptionPolicy.HandleException(ex, "Replace Policy");
if (rethrow)
throw;
}
Visual Basic
Try
' Run code.
Catch ex As Exception
Dim rethrow As Boolean = ExceptionPolicy.HandleException(ex, "Replace Policy")
If (rethrow) Then
Throw
End If
End Try
使用说明
在配置应用程序块以使用替换处理程序时考虑下面的信息。
一个经常进行的异常处理任务是用不同的异常包装一个异常。包装一个异常创建一个定义类型的新的异常,并设置原始异常为新异常的 InnerException 对象。使用在原始异常类型必须被映射到被应用程序架构中的其他层使用的新的异常类型的情况中的包装能力。可以封装和解释底层原始异常的细节,而不会丢失任 何关于异常的细节。可以将原始异常包装到已有的异常类型中,或者自己创建的定制异常类型中。下面说明了要包装异常时的情况:
典型目标
要用将一个异常包装到另一个中。应用程序在它的 catch 块中的代码类似于下列代码。
C#
catch(SomeException e)
{
CustomException myException = new CustomException(e);throw myException;
}
Visual Basic
Catch e As SomeException
Dim myException As CustomException = New CustomException(e)Throw myException
End Try
解决方案
在异常处理链中使用包装处理程序。
快速入门
对于如何使用异常应用程序块包装异常的扩展示例,请参见快速入门漫游,漫游:在另一个异常中包装一个异常。
使用包装处理程序
下面的过程描述了如何使用包装处理程序。
使用包装处理程序
C#
try
{
// Run code.
}
catch(Exception ex)
{
bool rethrow = ExceptionPolicy.HandleException(ex, "Wrap Policy");
if (rethrow)
throw;
}
Visual Basic
Try
' Run code.
Catch ex As Exception
Dim rethrow As Boolean = ExceptionPolicy.HandleException(ex, "Wrap Policy")
If (rethrow) Then
Throw
End If
End Try
使用说明
在配置应用程序块以使用包装处理程序时参见下面的信息。
一 个经常需要的异常处理任务是允许原始异常不改变的沿调用栈向上传播。可能要这样做是因为处理程序仅需要完成如记录不改变的异常日志这样的活动,或者因为其 他活动,如已关闭的包装和替换。例如,业务逻辑组件中的路由可能仅在检测到的异常点上记录日志。然后传播异常到调用者以进行其他处理。
典型目标
要让异常在异常处理程序链完成后沿调用栈不改变的向上传播。应用程序的 catch 块中有类似于以下的代码。
注意:代码不包括 FormatException 和 Logger.Log 方法。这些代码表示了典型的创建并记录格式化异常消息的应用程序代码。
C#
catch(SomeException e)
{
// Exception handling code to be done before propagating.
string formattedInfo = FormatException(e);
Logger.Log(e);throw e;
}
Visual Basic
Catch e As SomeException
' Exception handling code to be done before propagating.
Dim formattedInfo As String = FormatException(e)
Logger.Log(e)Throw e
End Try
快速入门
对于如何使用异常处理应用程序块传播原始异常的扩展示例,请参见快速入门漫游,漫游:传播原始异常。
解决方案
配置相关异常类型以使用 NotifyRethrow 做为它的 PostHandlingAction。
传播异常
下面的过程描述了如何使用异常处理块传播异常。
传播异常
C#
try
{
// Run code.
}
catch(Exception ex)
{
bool rethrow = ExceptionPolicy.HandleException(ex, "Propagate Policy");
if (rethrow)
{
// Throw original exception.
throw;
}
}
Visual Basic
Try
' Run code.
Catch ex As Exception
Dim rethrow As Boolean = ExceptionPolicy.HandleException(ex, "Propagate Policy")
If (rethrow) Then
' Throw original exception.
Throw
End If
End Try
可能要使用更适当的、用户友好的消息替换原始异常中的消息。要做到这一点,必须用另一个有与它相关的更适当的消息的异常来替换原始异常。例如,发生在应用程序的数据访问层的异常可以使用类型为 System.ApplicationException 的异常所替换。这使用消息:“应用程序现在无法处理您的请求。”,此消息然后显示给用户。
典型目的
在发生异常时显示用户友好的消息。应用程序的 catch 块中的代码类似于下面的代码。
注意:代码不包含 FormatException 和 Logger.Log 方法的实现。这些方法表示了典型的创建并记录格式化异常消息的方式。
C#
catch(SomeException e)
{
string formattedInfo = FormatException(e);
Logger.Log(formattedInfo);throw e;
}
Visual Basic
Catch e As SomeExceptionDim formattedInfo As String = FormatException(e)
Logger.Log(formattedInfo)Throw e
End Try
解决方案
使用包装处理程序或者替换处理程序创建带有适当消息的新异常。
快速入门
对于如何使用异常处理应用程序块显示用户友好消息的扩展示例,请参见快速入门漫游,漫游:通知用户。
显示用户友好的消息
下面的过程描述了如何使用异常处理块显示用户友好的消息。
显示用户友好消息
在使用异常处理应用程序块时,一个经常需要的任务是在异常发生时通知用户。(通常,这在消息被更改为对于特定用户来说更好用的消息之后完成。更多信息,请 参见显示用户友好消息。)依赖于应用程序的类型,可以使用 Windows 窗口对话框或者 Web 页面来做这一点。当应用程序中的异常无法处理时,用户必须知道是什么出现了错误,并带有他或她下一步该做什么的指导。
典型目标
通知用户发生了异常。
解决方案
创建为用户构建和显示消息的定制异常处理程序。为应用程序构建处理程序为全局异常处理程序。包括在异常处理链中的处理程序。
快速入门
对于如何使用异常处理应用程序块通知用户的扩展示例,请参见快速入门漫游,漫游:通知用户。
通知用户
下面的过程描述了如何使用异常处理块通知异常的用户。
通知用户
1. 创建派生自 TextExceptionFormatter 类,它将为显示给用户而格式化消息。下面的代码示范了如何创建一个客户格式化程序,它在消息中不包括栈跟踪信息。
C#
public class AppTextExceptionFormatter : TextExceptionFormatter
{
public AppTextExceptionFormatter(TextWriter writer, Exception exception): base (writer, exception)
{
}protected override void WriteStackTrace(string stackTrace)
{
}protected override void WriteExceptionType(Type exceptionType)
{
base.Indent();
base.Writer.WriteLine("Type : {0}", exceptionType.FullName);
}
}
Visual Basic
Public Class AppTextExceptionFormatter
Inherits TextExceptionFormatterPublic Sub New(ByVal writer As TextWriter, ByVal exception As Exception)
MyBase.New(writer, exception)
End SubProtected Overrides Sub WriteStackTrace(ByVal stackTrace As String)
End SubProtected Overrides Sub WriteExceptionType(ByVal exceptionType As Type)
MyBase.Indent()
MyBase.Writer.WriteLine("Type : {0}", exceptionType.FullName)
End Sub
End Class
2. 创建显示对话框以通知异常的用户的定制异常处理程序。下面的代码示范了如何来做这一点。
C#
[ConfigurationElementType(typeof(CustomHandlerData))]
public class AppMessageExceptionHandler : IExceptionHandler
{
public AppMessageExceptionHandler(NameValueCollection ignore)
{
}public Exception HandleException(Exception exception, Guid handlingInstanceId)
{
DialogResult result = this.ShowThreadExceptionDialog(exception);return exception;
}// Creates the error message and displays it.
private DialogResult ShowThreadExceptionDialog(Exception ex)
{
string errorMsg = "The following exception was caught by the Quick Start Global Exception Handler:" + Environment.NewLine + Environment.NewLine;StringBuilder sb = new StringBuilder();
StringWriter writer = new StringWriter(sb);AppTextExceptionFormatter formatter = new AppTextExceptionFormatter(writer, ex);
// Format the exception.
formatter.Format();errorMsg += sb.ToString();
return MessageBox.Show(errorMsg, "Application Error", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}}
Visual Basic
<ConfigurationElementType(GetType(CustomHandlerData))> _
Public Class AppMessageExceptionHandler
Implements IExceptionHandlerPublic Sub New(ByVal ignore As NameValueCollection)
End Sub
Public Function HandleException(ByVal e As Exception, ByVal handlingInstanceID As Guid) As Exception Implements IExceptionHandler.HandleException
Dim result As DialogResult = Me.ShowThreadExceptionDialog(e)
Return e
End Function' Creates the error message and displays it.
Private Function ShowThreadExceptionDialog(ByVal e As Exception) As DialogResultDim errorMsg As String = "The following exception was caught by the Quick Start Global Exception Handler:" + Environment.NewLine + Environment.NewLine
Dim sb As StringBuilder = New StringBuilder
Dim writer As StringWriter = New StringWriter(sb)Dim formatter As AppTextExceptionFormatter = New AppTextExceptionFormatter(writer, e)
' Format the exception.
formatter.Format()errorMsg += sb.ToString()
Return MessageBox.Show(errorMsg, "Application Error", MessageBoxButtons.OK, MessageBoxIcon.Stop)
End FunctionEnd Class
3. 为应用程序创建使用相关异常类型的异常处理策略。
4. 配置异常类型。指定 PostHandlingAction 为 None。None 活动指出了应用程序块在异常处理程序链运行后没有进一步的活动。
5. 为特定异常类型添加新的定制处理程序,设置处理程序类型为在第一步中创建的新处理程序。
6. 修改应用程序代码以在异常发生时执行新的策略。下面的代码示范了如何来做这一点。
C#
try
{
// Run code.
}
catch(Exception ex)
{
bool rethrow = ExceptionPolicy.HandleException(ex, "Global Policy");
if (rethrow)
throw;
}
Visual Basic
Try
' Run code.
Catch ex As Exception
Dim rethrow As Boolean = ExceptionPolicy.HandleException(ex, "Global Policy")
If (rethrow) Then
Throw
End If
End Try
使用说明
从来不要在服务器应用程序如 ASP.NET 应用程序和企业服务应用程序中使用显示 Windows 窗口或触发消息对话框的处理程序。这样做会导致应用程序停止响应。
在使用异常处理应用程序块时,一个经常需要的任务是将允许支持人员访问详细信息以帮助发生异常的用户。在异常发生且没有处理时,用户通常展示的是友好的错 误消息。用户可能不得不呼叫支持人员,然后支持人员可能需要比用户错误消息更多的消息,以确定发生了什么错误以及如何修正问题。此场景示范了如何用可以被 支持人员访问的详细异常日志匹配用户的错误消息。
典型目标
支持开发人员能够用异常日志中的包含在原始异常中的详细信息匹配用户友好错误消息。
解决方案
要使用异常管理和跟踪进行帮助,应用程序块为每个异常的处理都生成了一个 HandlingInstanceID 。可以使用 HandlingInstanceID 映射错误消息到发生的特定异常。HandlingInstanceID 唯一用于每个处理的异常,并且与异常处理应用程序块中的处理链相关。
HandlingInstanceID 被传递给特定异常处理链中的每个处理程序。因此,在捕获原始异常信息和它的相关 HandlingInstanceID 后,将可以跟踪穿越所有处理活动的特定异常。可能,例如,记录带有 HandlingInstanceID 的原始异常,然后将 HandlingInstanceID 显示在给用户的消息中。同样的 HandlingInstanceID ,与作为链中的第一步的原始异常一起被记录,以跟踪导致用户和支持通知的原始异常。
快速入门
对于如何使用 HandlingInstanceID 以允许支持人员访问详细信息的扩展示例,请参见快速入门漫游,漫游:通知用户。
协助支持人员
下面的过程描述了如何通过提供异常信息以协助支持人员。
协助支持人员
下面的代码展示了如何传递可被替换的异常到异常处理应用程序块。代码检查从 HandleException 方法中返回的值是 true 还是 false ,以指出配置指定的原始异常是否将被再次抛出。
C#
try
{
// Run code.
}
catch(Exception ex)
{
bool rethrow = ExceptionPolicy.HandleException(ex, "Replace Policy");
if (rethrow)
throw;
}
Visual Basic
Try
' Run code.
Catch ex As Exception
Dim rethrow As Boolean = ExceptionPolicy.HandleException(ex, "Replace Policy")
If (rethrow) Then
Throw
End If
End Try
使用说明
在发送一个通知给用户和包含用于支持人员的信息时,请参考下面的信息:
在 Windows Communication Foundation (WCF) 中,未知的异常不能发送给客户应用程序,为了防止服务实现的细节从服务的安全边界泄出。这通过在 WCF 配置中的 元素的 includeExceptionDetailInFaults 属性控制。要开启异常隐藏,此属性必须设置为“false”。如果在配置文件中没有指定,此属性设置为 false 。
注意:includeExceptionDetailInFaults 配置设置仅用于未知或未绑定的异常。它对已知异常没有任何影响,这是操作有与已知失败类型一起的 FaultContract 的地方,然后,操作在失败契约中的 knownFault 地方抛出 FaultException<knownFault> 。
异常隐藏有助于防止 Web 服务在异常发生时泄露关于服务内部实现的信息,下面重点介绍了为什么要使用异常隐藏:
只有已被消除危险或者被安全的设计的异常才能返回给客户应用程序。安全设计的异常在异常消息中不包含敏感信息,它不包含堆栈跟踪的细节,以及其他可能揭示 Web 服务内部工作的敏感信息。可以使用异常隐藏模式来通过使用完全设计的异常替换以消除不安全的异常。
异常处理应用程序块包含了对在 WCF 服务边界上异常隐藏的支持。这些支持以下面这些部分组成:
使用 ExceptionShieldingAttribute
在 WCF 服务中开启异常隐藏
C#
[ServiceContract]
public interface IQuoteService
{
[OperationContract]
[FaultContract(typeof(FaultContracts.SystemUnavailableFault))]
QuoteResponseType GetQuote(QuoteRequestType request);
}[ExceptionShielding("QuoteServicePolicy")]
public class QuoteService : IQuoteService
{
public QuoteResponseType GetQuote(QuoteRequestType request)
{
// Method code here...
}
}
Visual Basic
<ServiceContract> _
Public Interface IQuoteService<OperationContract> _
<FaultContract(GetType(FaultContracts.SystemUnavailableFault))> _
Function GetQuote(request As QuoteRequestType) As QuoteResponseType
End Interface<ExceptionShielding("QuoteServicePolicy")> _
Public Class QuoteService : Implements IQuoteServicePublic Function GetQuote(request As QuoteRequestType) As QuoteResponseType
Implements IQuoteService.GetQuote
' Method code here...
End Function
End Class
使用 Fault Contract Exception Handler
在为 WCF 应用程序中的异常隐藏使用异常处理应用程序块时,可以使用 Fault Contract Exception Handler 来转换运行时异常到适当的 Fault Contract 类型。此异常处理程序也让你能够映射来自原始异常的属性和处理实现的 Id 到 Fault Contract 中的属性。
使用 Fault Contract Exception Handler
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。