我正在使用企业库来基于Guy Burstein的博客文章here实现异常屏蔽。我的实现与他的实现基本相同,但是我有两个问题:
1:屏蔽异常的要点是不传递错误的确切细节,因此,为什么映射指定从原始异常中传递消息不变。提供不太具体的信息的明智方式是什么?
2:传回的FaultException包含来自原始异常的消息,因此,无论我设法包装或返回故障合同中的内容如何,都可以使用有关FaultException的详细信息。有没有一种方法可以将信息删除回通用的“内部错误”消息。
请注意,如果我不使用[ExceptionShielding]
和[FaultContract]
属性,则该服务将返回标准“服务器由于内部错误而无法处理该请求”消息。
如果知道自己有不泄露敏感信息的应用程序异常,则可以处理这些特定的异常并映射message属性。对于其他例外,您可以跳过映射消息。另外,您可以在故障协定本身上指定exceptionMessage:
<add type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
postHandlingAction="ThrowNewException" name="Exception">
<exceptionHandlers>
<add exceptionMessage="Oops! A System Error Occurred in the Service Layer." faultContractType="MyTypes.Exceptions.ServiceFault, MyTypes.Exceptions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF.FaultContractExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="Default Fault Contract Handler">
</add>
exceptionMessage
将填充在FaultException的Message属性上。如果您不映射详细信息,那么对您而言可能就足够了。
如果您确实想填充故障类中的值,则可以分两个步骤进行:
使用Guy Burstein's WCF Exception Handling with Exception Handling Application Block Integration示例,这将设置ServiceFault的MessageText(其余部分基于该示例。)>
所以您的服务将如下所示:
public int CreateOrder(string currency, double amount) { try { throw new InvalidOperationException("Cannot call this operation!"); } catch (Exception e) { // This sanitizes the message and throws a new Exception Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicy. HandleException(e, "SanitizeAndThrow"); } return 0; }
然后在配置中,您将创建SanitizeAndThrow处理程序以清理消息:
<add name="SanitizeAndThrow"> <exceptionTypes> <add type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" postHandlingAction="ThrowNewException" name="Exception"> <exceptionHandlers> <add exceptionMessage="This is a sanitized message." replaceExceptionType="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ReplaceHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling" name="Replace Handler" /> </exceptionHandlers> </add> </exceptionTypes> </add>
然后您可以使用异常屏蔽来创建FaultException:
<add name="WCF Exception Shielding"> <exceptionTypes> <add type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" postHandlingAction="ThrowNewException" name="Exception"> <exceptionHandlers> <add exceptionMessage="Oops!" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF.FaultContractExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF" name="DefaultFaultContract Handler" faultContractType="Bursteg.Samples.WCFIntegration.ServiceContracts.ServiceFault, Bursteg.Samples.WCFIntegration.ServiceContracts"> <mappings> <add name="Id" source="{Guid}"/> <add name="MessageText" source="{Message}"/> </mappings> </add> </exceptionHandlers> </add>
关于此示例的一些注释:
如果不清除异常,则可能泄漏消息。可以通过让“ SanitizeAndThrow”处理函数抛出您自己的自定义异常并由屏蔽策略来处理您的自定义类型并映射Message,但对于任何其他类型则不执行任何映射来缓解这种情况。
此代码尚不支持生产,因此不符合最佳实践。这仅仅是一个例子,也是一个起点。例如您通常不想捕获一般的Exception
,服务代码没有NotifyRethrow逻辑,等等。
如果需要,您可以创建一个自定义的故障合同处理程序来处理更复杂的情况。
也许有一种更简单的方法来清除故障异常的Detail
(例如,异常屏蔽中的链接处理程序)?