Enterprise Library 异常处理应用程序块关键场景

本文档维护在: http://wiki.entlib.net.cn/EntlibHelp31ExceptionHandlingApplicationBlock.ashx

此主题描述了开发人员在处理异常时必须解决的绝大多数常见情况。每个场景解释了任务、描述了任务可能发生的真实世界情况,还包括了示范了如何使用异常处理应用程序块完成任务的代码。场景如下:
  • 记录异常日志。此场景示范了如何使用日志处理程序收集异常信息、格式化它,然后将它发送给日志应用程序块。
  • 包装异常。此场景示范了如何使用包装处理程序创建一个定义的类型的新的异常,它使用更加相关的另一个异常包装原始异常。
  • 替换异常。此场景示范了如何使用替换处理程序创建一个定义的类型的新的异常,它替换了原始异常。
  • 传播异常。此场景示范了如何在运行了一连串的异常处理程序后以它的原始状态传播异常。
  • 显示用户友好的信息。此场景示范了如何使用提供用于用户的支持或指令信息的异常替换或者包装异常。
  • 通知用户。此场景示范了用于让用户知道什么发生了错误的方法。
  • 协助支持人员。此场景示范了支持人员如何能用细节匹配用户的错误信息。

在异常处理过程中发生的异常

异 常可以发生在使用异常处理应用程序块进行异常处理时。这些异常通常是因为应用程序代码指定的异常处理策略不是应用程序配置的一部分,或者定制的异常处理程 序中有错误的代码。异常还可以发生在配置信息不可用的时候(例如,它没有包含有效的 XML )。因为异常可能包含敏感信息,应用程序块不会返回原始异常给应用程序,而是抛出一个新的异常。

如果应用程序配置信息无效,应用程序块会抛出 System.Configuration.ConfigurationErrorsException 类型的异常。在此异常抛出前,不会记录任何信息。

如果配置文件是有效的,应用程序块抛出 ExceptionHandlingException 类型的异常。应用程序块使用度量设置来决定原始的异常信息是否被记录日志。如果度量是可用的,应用程序块在抛出新的异常前在应用程序事件日志中记录原始异常信息。

4.1 - 记录异常日志

经常需要的异常处理任务是记录与异常关联的信息为日志。异常处理应用程序块,与日志应用程序块联合,让你在配置文件中指定的地方记录格式化的异常信息。例如,客户应用程序通常在事件日志中记录应用程序信息,而电子商务应用程序的服务器组件可能在数据库中记录异常日志。

典型目标

要在任何其他异常处理发生前记录发生在应用程序层某层中的异常。应用程序中有类似于下列代码的代码在它的 catch 块中。

注意:代码不包含 FormatExceptionLogger.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

解决方案

指派日志处理程序为策略的异常处理链中的第一个处理程序。异常处理应用程序块包含日志处理程序。

快速入门

关于如何记录异常日志的扩展示例,请参见快速入门漫游,漫游:记录异常日志。

使用日志处理程序

要使用日志处理程序,必须配置应用程序异常策略和日志应用程序块。必须修改应用程序以使用适当的异常处理策略。

配置应用程序异常策略

  1. 使用配置控制台创建用于应用程序层的异常处理策略。更多信息,请参见输入配置信息。
  2. 指定要处理和记录日志的异常类型。
  3. 为每个异常类型添加日志处理程序为第一个处理程序。
  4. 配置日志信息程序:
    • 输入事件 ID。
    • 输入日志类型。
    • 选择严重度。
    • 输入日志条目的标题。
    • 选择格式化程序的类型名称。
    • 输入优先级。
  5. 添加任何其他异常处理程序以在日志处理程序之后调用。

配置日志应用程序块

  1. 添加日志应用程序块到应用程序配置中(添加日志处理程序将自动添加日志应用程序块到应用程序配置中)。更多信息,请参见日志应用程序块文档。
  2. 配置日志应用程序块。

修改应用程序

修改应用程序代码以在异常发生时执行新的策略。下面的代码示范了如何来做这件事。候选的名称 “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

使用提示

在配置应用程序块以使用日志处理程序时,请参考下面的信息。

  • 异常可以在处理期间任何时候被记录,它们无须在事件处理队列开始时记录日志。例如,可以在包装或者替换后记录异常。
  • 异常处理应用程序块提供了依赖于日志应用程序块的日志异常处理程序。还可以加入定制的日志功能到异常处理程序中以使用日志应用程序块的代替品。
  • 上面的代码示例使用了一个用于所有可管理的异常的单一的通用处理程序(这些异常派生自 System.Exception 类)。应用程序可以有用不同策略调用 HandleException 方法的其他 catch 语句,或者不使用异常处理应用程序块。在此示例中的代码使用了策略名“Logging Policy”以强调它的行为。通常,策略名称反映了使用它的应用程序层或者组件,而不是功能。例如,用于数据访问层的策略将被命令为“Data Access Layer Policy”。

4.2 - 替换异常

经常需要的异常处理任务是用另一个异常替换原始异常。例如,如果异常要穿越信任边界,而你不想发送原始的异常,因为它包含了敏感信息。

典型目标

要用另一个更合适的异常替换包含敏感或者不需要的信息的原始异常,在应用程序的 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

解决方案

在异常处理链中使用替换处理程序。在传播异常到应用程序层外之前执行策略。

快速入门

如何使用异常处理应用程序块替换异常的扩展示例,请参见快速入门漫游,漫游:用另一个异常替换一个异常。

使用替换处理程序

下面的过程描述了如何使用替换处理程序。

使用替换处理程序

  1. 为应用程序创建使用合适的异常类型的异常处理策略。更多信息,请参见输入配置信息。
  2. 配置异常类型,指定 PostHandlingActionThrowNewException。这将导致应用程序块抛出通过替换原始异常创建的新异常。抛出发生在所有处理程序链运行之后。
  3. 为特定异常类型添加新的替换处理程序。
  4. 配置替换处理程序。添加使用的异常消息和用于替换原始异常的异常类型。
  5. 修改应用程序代码,以在异常发生时执行新的策略。下列代码展示了如何进行此工作。使用自己的替换策略的名称替换名称"Replace Policy"。

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

使用说明

在配置应用程序块以使用替换处理程序时考虑下面的信息。
  • 通常,异常在以原始状态记录日志后被替换。
  • 要帮助异常的管理和跟踪,应用程序块生成了一个 HandlingInstanceID ,它可以用来映射到原始异常。要使用 HandlingInstanceID ,必须在配置文件中的异常消息中包含{handlingInstanceID}令牌。HandlingInstanceIDGUID 类型的。应用程序块抛出的异常是最终的异常,这个异常是整个处理程序链运行后的结果。例如,如果链指定异常 A 用异常 B 来替换,后面的处理程序用异常 C 来替换异常 B ,异常 C 将被抛出。
  • 应用程序代码将总是检查返回值,并且假定它与配置的值相同。这意味着,即使配置数据发生改变,应用程序代码也会有正确的功能,并且不用修改。
  • 替换处理程序仅有一个接收 string 类型的参数的构造函数。这意味着,必须为所有用于替换其他异常的定制异常必须提供此构造函数的重载。

4.3 - 包装异常

一个经常进行的异常处理任务是用不同的异常包装一个异常。包装一个异常创建一个定义类型的新的异常,并设置原始异常为新异常的 InnerException 对象。使用在原始异常类型必须被映射到被应用程序架构中的其他层使用的新的异常类型的情况中的包装能力。可以封装和解释底层原始异常的细节,而不会丢失任 何关于异常的细节。可以将原始异常包装到已有的异常类型中,或者自己创建的定制异常类型中。下面说明了要包装异常时的情况:
  1. 名为 Update Customer 的业务服务调用了数据层的服务。
  2. 数据服务层失败并抛出异常。这可以是指出更新失败的众多异常中的任何一个。某些异常集指出可能用重试来恢复(例如,如果记录被锁定),而其他的不能恢复(例如,如果是并发错误或者脏记录)。
  3. 异常处理程序映射并包装这些异常集到二个异常类型中:RecoverableUpdateException FatalUpdateException
  4. 业务服务基于包装类型来处理异常,并执行适当的活动,即使它与底层失败的详细信息分离。

典型目标

要用将一个异常包装到另一个中。应用程序在它的 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

解决方案

在异常处理链中使用包装处理程序。

快速入门

对于如何使用异常应用程序块包装异常的扩展示例,请参见快速入门漫游,漫游:在另一个异常中包装一个异常。

使用包装处理程序

下面的过程描述了如何使用包装处理程序。

使用包装处理程序

  1. 创建包含适当的用于应用程序的异常类型。更多信息,请参见输入配置信息。
  2. 配置异常类型,指定 PostHandlingActionThrowNewException。这意味着应用程序块将抛出通过包装原始异常创建的新的异常。抛出发生在整个处理程序链运行之后。
  3. 为特定异常类型添加新的包装处理程序。
  4. 配置包装处理程序。添加要被使用的异常消息和将包装原始异常的异常类型。
  5. 修改应用程序代码以在异常发生时执行新的策略,就像展示在下面的代码一样。将“Wrap Policy”换成自己的策略的名称。

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

使用说明

在配置应用程序块以使用包装处理程序时参见下面的信息。
  • 通常,异常在它们被以原始状态记录日志后被包装。
  • 要帮助异常的管理和跟踪,应用程序块生成可用于映射到原始异常的 HandlingInstanceID 对象。
  • 如果之后的处理活动被设置为 ThrowNewException ,被应用程序块抛出的异常是最终的异常,将是运行整个处理程序链的结果。(如果链指定异常 A 要被异常 B 包装,后面的处理程序用异常 C 替换了异常 B ,应用程序块在后面的处理活动被设置为 ThrowNewException 时抛出异常 C 。
  • 如果后面的处理活动被设置为 NotifyRethrow ,应用程序块被返回 true 给调用代码。这允许代码抛出原始的异常。
  • 应用程序代码将总是检查返回值,而不是假设它是与配置的值相同的值。即使配置数据已改变,如果应用程序代码检查返回的值,应用程序代码也会有正确的功能且不需要修改。
  • 用于包装另一个异常的异常类型必须有接收二个参数:string 和异常对象的构造函数。这意味着必须为用于包装其他异常的定制异常类型提供这个构造函数重载。

4.4 - 传播异常

一 个经常需要的异常处理任务是允许原始异常不改变的沿调用栈向上传播。可能要这样做是因为处理程序仅需要完成如记录不改变的异常日志这样的活动,或者因为其 他活动,如已关闭的包装和替换。例如,业务逻辑组件中的路由可能仅在检测到的异常点上记录日志。然后传播异常到调用者以进行其他处理。

典型目标

要让异常在异常处理程序链完成后沿调用栈不改变的向上传播。应用程序的 catch 块中有类似于以下的代码。

注意:代码不包括 FormatExceptionLogger.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

传播异常

下面的过程描述了如何使用异常处理块传播异常。

传播异常

  1. 为应用程序创建使用相关异常类型的异常处理策略。更多信息,请参见输入配置信息。
  2. 配置异常类型。指定 PostHandlingActionNotifyRethrow 。这导致应用程序块从 HandleException 方法调用中返回 true 给应用程序。
  3. 修改应用程序代码以在异常发生时执行新的策略。
  4. 检查来自 HandleException 调用的返回值。如果返回值是 true ,执行 throw 语句,就像展示在版面的代码示例一样。

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

4.5 - 显示用户友好消息

可能要使用更适当的、用户友好的消息替换原始异常中的消息。要做到这一点,必须用另一个有与它相关的更适当的消息的异常来替换原始异常。例如,发生在应用程序的数据访问层的异常可以使用类型为 System.ApplicationException 的异常所替换。这使用消息:“应用程序现在无法处理您的请求。”,此消息然后显示给用户。

典型目的

在发生异常时显示用户友好的消息。应用程序的 catch 块中的代码类似于下面的代码。

注意:代码不包含 FormatExceptionLogger.Log 方法的实现。这些方法表示了典型的创建并记录格式化异常消息的方式。

C#
catch(SomeException e)
{
string formattedInfo = FormatException(e);
Logger.Log(formattedInfo);

throw e;
}

Visual Basic
Catch e As SomeException

Dim formattedInfo As String = FormatException(e)
Logger.Log(formattedInfo)

Throw e
End Try

解决方案

使用包装处理程序或者替换处理程序创建带有适当消息的新异常。

快速入门

对于如何使用异常处理应用程序块显示用户友好消息的扩展示例,请参见快速入门漫游,漫游:通知用户。

显示用户友好的消息

下面的过程描述了如何使用异常处理块显示用户友好的消息。

显示用户友好消息

  1. 使用配置控制台创建使用用于应用程序的相关异常类型创建异常处理策略。更多信息,请参见输入配置信息。
  2. 配置异常类型。指定 PostHandlingActionThrowNewExceptionThrowNewException 活动指出了应用程序块从链中的最后一个异常处理程序返回时将抛出异常。
  3. 为特定异常类型添加新的包装异常处理程序。
  4. 用新的异常类型和友好消息配置包装异常程序。
  5. 修改应用程序代码以在异常发生时执行新的策略。

4.6 - 通知用户

在使用异常处理应用程序块时,一个经常需要的任务是在异常发生时通知用户。(通常,这在消息被更改为对于特定用户来说更好用的消息之后完成。更多信息,请 参见显示用户友好消息。)依赖于应用程序的类型,可以使用 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 TextExceptionFormatter

Public Sub New(ByVal writer As TextWriter, ByVal exception As Exception)
MyBase.New(writer, exception)
End Sub

Protected Overrides Sub WriteStackTrace(ByVal stackTrace As String)
End Sub

Protected 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 IExceptionHandler

Public 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 DialogResult

Dim 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 Function

End Class

3. 为应用程序创建使用相关异常类型的异常处理策略。

4. 配置异常类型。指定 PostHandlingActionNoneNone 活动指出了应用程序块在异常处理程序链运行后没有进一步的活动。

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 窗口或触发消息对话框的处理程序。这样做会导致应用程序停止响应。

4.7 - 协助支持人员

在使用异常处理应用程序块时,一个经常需要的任务是将允许支持人员访问详细信息以帮助发生异常的用户。在异常发生且没有处理时,用户通常展示的是友好的错 误消息。用户可能不得不呼叫支持人员,然后支持人员可能需要比用户错误消息更多的消息,以确定发生了什么错误以及如何修正问题。此场景示范了如何用可以被 支持人员访问的详细异常日志匹配用户的错误消息。

典型目标

支持开发人员能够用异常日志中的包含在原始异常中的详细信息匹配用户友好错误消息。

解决方案

要使用异常管理和跟踪进行帮助,应用程序块为每个异常的处理都生成了一个 HandlingInstanceID 。可以使用 HandlingInstanceID 映射错误消息到发生的特定异常。 HandlingInstanceID 唯一用于每个处理的异常,并且与异常处理应用程序块中的处理链相关。

HandlingInstanceID 被传递给特定异常处理链中的每个处理程序。因此,在捕获原始异常信息和它的相关 HandlingInstanceID 后,将可以跟踪穿越所有处理活动的特定异常。可能,例如,记录带有 HandlingInstanceID 的原始异常,然后将 HandlingInstanceID 显示在给用户的消息中。同样的 HandlingInstanceID ,与作为链中的第一步的原始异常一起被记录,以跟踪导致用户和支持通知的原始异常。

快速入门

对于如何使用 HandlingInstanceID 以允许支持人员访问详细信息的扩展示例,请参见快速入门漫游,漫游:通知用户。

协助支持人员

下面的过程描述了如何通过提供异常信息以协助支持人员。

协助支持人员

  1. 使用配置控制台为应用程序创建使用相关异常类型的异常处理策略。更多信息,请参见输入配置信息。
  2. 配置异常类型。指定适当的 PostHandlingAction。指定 None 指出应用程序块在异常处理程序链运行后没有进一步的活动。这适用于包含 handlingInstanceID 的消息将通过在同一处理程序链中的异常处理程序显示时。指定 ThrowNewException 导致应用程序块在整个处理程序链运行后抛出包含带有 handlingInstanceID 的消息的新异常。这适用于在包含 handlingInstanceID 的消息通过不是当前异常处理程序链的一部分的 UI 组件显示的时候。
  3. 添加日志处理程序以捕获原始异常信息。
  4. 为特定异常类型添加新的替换处理程序。
  5. 配置替换处理程序,在消息体中包含令牌 {handlingInstanceID} 。在替换处理程序运行时,令牌将被应用程序块生成的相关标识所替换。
  6. 添加将显示异常消息给用户的定制异常处理程序。关于如何创建用于显示异常消息的定制处理程序,请参见通知用户。
  7. 修改应用程序代码以在异常发生时执行新的策略。

下面的代码展示了如何传递可被替换的异常到异常处理应用程序块。代码检查从 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

使用说明

在发送一个通知给用户和包含用于支持人员的信息时,请参考下面的信息:
  • handlingInstanceID 显示在窗体或者文本框中,以让用户可以很容易的将它复制到剪贴板中。
  • 提示用户在异常发生时进入将执行的活动。记录此信息到支持人员可以获取到然后用原始异常关联它的地方。

4.8 - 在 WCF 服务边界屏蔽异常

在 Windows Communication Foundation (WCF) 中,未知的异常不能发送给客户应用程序,为了防止服务实现的细节从服务的安全边界泄出。这通过在 WCF 配置中的 元素的 includeExceptionDetailInFaults 属性控制。要开启异常隐藏,此属性必须设置为“false”。如果在配置文件中没有指定,此属性设置为 false 。

注意includeExceptionDetailInFaults 配置设置仅用于未知或未绑定的异常。它对已知异常没有任何影响,这是操作有与已知失败类型一起的 FaultContract 的地方,然后,操作在失败契约中的 knownFault 地方抛出 FaultException<knownFault>

异常隐藏有助于防止 Web 服务在异常发生时泄露关于服务内部实现的信息,下面重点介绍了为什么要使用异常隐藏:
  • 异常细节可能包含攻击都可以用来利用系统使用的资源的规则。
  • 与预计异常相关的信息需要返回给客户应用程序。
  • 发生在 Web 服务中的异常将被记录日志以支持疑难解答。

只有已被消除危险或者被安全的设计的异常才能返回给客户应用程序。安全设计的异常在异常消息中不包含敏感信息,它不包含堆栈跟踪的细节,以及其他可能揭示 Web 服务内部工作的敏感信息。可以使用异常隐藏模式来通过使用完全设计的异常替换以消除不安全的异常。

异常处理应用程序块包含了对在 WCF 服务边界上异常隐藏的支持。这些支持以下面这些部分组成:
  • ExceptionShieldingAttribute,它用于关联异常处理策略和 WCF 服务操作。
  • FaultContractExceptionHandler,它可以转换异常到 Fault Contract 的特定类型,并映射期望的异常属性到 Fault Contract 。

使用 ExceptionShieldingAttribute

在 WCF 服务中开启异常隐藏

  1. 添加到下列程序集的引用:
    • Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.dll。
    • Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.dll
    • Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF.dll
    • Microsoft.Practices.EnterpriseLibrary.Common.dll
    • Microsoft.Practices.ObjectBuilder.dll
  2. 添加 Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF 的 using 语句。
  3. 添加 ExceptionShielding 属性到服务实现类或者服务契约接口,并指定异常策略的名称以用做构造函数的参数。如果没有在构造函数参数中指定策略的名称,或者指定的策略没有定义在配置中,隐藏实现总是会查找名为“WCF Exception Shielding”的策略。
  4. 添加异常处理应用程序块配置节到服务的 Web.config 文件中,然后定义期望的异常策略和处理程序。Fault Mapping 异常处理程序将被用于映射异常到定义在操作契约中的失败契约。此异常处理程序将在后面的节中描述。
  5. 在服务的客户应用程序中实现异常处理逻辑以捕获服务的可能异常,然后适当的处理它们。
  6. 下面的代码展示了 ExceptionShielding 属性应用到服务的实现类,以及它的相应服务契约指定了可能由操作返回的失败契约:

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 IQuoteService

Public 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

  1. 为应用程序创建包含适当异常类型的异常处理策略。更多信息,请参见输入配置信息。
  2. 配置异常类型,指定 PostHandlingActionThrowNewException。应用程序块将抛出通过包装原始异常创建的新的异常。抛出发生在整个处理程序链运行之后。
  3. 为指定的异常类型添加新的 Fault Contract Exception Handler 。
  4. 配置 Fault Contract Exception Handler :
    1. 指定期望的将被返回给客户的 Fault Contract 类型
    2. 添加用于将被返回给客户的 Fault Contract 的异常消息
    3. 可选的,配置来自原始异常的什么属性将被映射到 Fault Contract 。在 FaultContractPropertyMapping 编辑器对话框中,为每个要映射的属性添加一个条目。Name 属性是 Fault Contract 上属性的名称。Source 属性指定原始异常的属性的名称,它是将被获取的值。还可以指定“{Guid}”的 Source 以添加当前处理实例 Id 到 Fault Contract 属性。
    4. Fault Contract Exception Handler 将自动映射来自异常的任何属性到 Fault Contract ,如果它们的名称匹配且类型兼容的话。如果要防止这样,可以添加一个带有 Fault Contract 属性名称的 NameSource 是空字符串的映射。


转载于:https://www.cnblogs.com/doriandeng/archive/2007/12/11/991485.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值