Welcome

首页 / 软件开发 / WCF / WCF技术剖析之二十一:WCF基本异常处理模式[中篇]

WCF技术剖析之二十一:WCF基本异常处理模式[中篇]2012-11-14 cnblogs Artech通过WCF基本的异常处理模式[上篇], 我们知道了:在默认的情况下,服务端在执行某个服务操作时抛出的异常(在这里指非FaultException异常),其相关的错误信息仅仅限于服务端可见,并不会被WCF传递到客户端;如果将开启了IncludeExceptionDetailInFaults的ServiceDebug服务行为通过声明(通过在服务类型上应用ServiceBehaviorAttrite特性)或者配置的方式应用到相应的服务上,异常相关的所有细节信息将会原封不动地向客户端传送。

这两种方式体现了两种极端的异常传播(Exception Propagation)机制,对于基于服务操作执行过程中抛出的异常的错误细节,要么完全对客户端屏蔽,要么全部暴露于客户端。在真正通过WCF来架构我们的分布式系统中,我们往往需要一种折中的异常传播机制:自定义服务端异常信息。这样既可以让客户端得到一个易于理解的错误信息,又在一定程度上避免了一些敏感信息的泄露。

一、 通过FaultException直接指定错误信息

对于执行服务操作中抛出的异常,如果服务的定义者仅仅希望服务的调用者得到一段自定义的错误信息文本(字符串),我们要做的实际上很简单:在服务操作中直接抛出一个FaultException异常,该异常对象通过以字符串形式体现的自定义错误信息创建。下面的代码中,CalculaorService的Divide方式在指定的时候对第二参数进行了验证,如果为零则创建一个FaultException,并指定错误信息(“被除数y不能为零!”)。

 1: using System.ServiceModel;
2: using Artech.WcfServices.Contracts;
3: namespace Artech.WcfServices.Services
4: {
5: [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
6: public class CalculatorService : ICalculator
7: {
8: public int Divide(int x, int y)
9: {
10: if (0 == y)
11: {
12: throw new FaultException("被除数y不能为零!");
13: }
14: return x / y;
15: }
16: }
17: }
客户端在调用该服务操作的时候,如果传入零作为被除数,将会直接捕获服务端定义的抛出的这个异常(实际上,这其中经历了异常对象的序列化、消息交换以及异常对象的反序列化等一系列的操作)。客户端具体的异常捕获情况如下面的程序体现:

 1: using System;
2: using System.ServiceModel;
3: using Artech.WcfServices.Contracts;
4: namespace Artech.WcfServices.Clients
5: {
6: class Program
7: {
8: static void Main(string[] args)
9: {
10: using (ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>(
11:"calculatorservice"))
12: {
13: ICalculator calculator = channelFactory.CreateChannel();
14: using (calculator as IDisposable)
15: {
16: try
17: {
18: int result = calculator.Divide(1, 0);
19: }
20: catch (FaultException ex)
21: {
22: Console.WriteLine(ex.Message);
23: (calculator as ICommunicationObject).Abort();
24: }
25: }
26: }
27: }
28: }
29: }
输出结果:

被除数y不能为零!

虽然在很多情况下,在服务端指定服务操作的过程中直接抛出含有自定义错误信息的FaultException异常,就能过客户端感知到遇到的具体错误并进行必要的排错和纠错。但是,我们更多地,还是倾向于直接定义一个类型来描述异常信息。我个人倾向于这样一类的类型为错误明细类型(Fault Detail Type)。服务端根据具体的异常场景创建相应的错误类型对象,并基于该对象我们上面提到的System.ServiceModel.FaultException<TDetail>异常,其中泛型类型参数为异常细节类型。在这个过程中,还涉及到一个重要的概念:错误契约(Fault Contract),接下来,我们就来介绍一下FaultException<TDetail>和错误契约。