在WCF中,在服务器抛出的任何异常,如果未做特别处理,在客户端都只能被FaultException捕获,比如如下示例:
声明契约
[ServiceContract]
public
interface IMyContract
{
[OperationContract]
double Division(double x, double y);
}
实现服务
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class MyContract : IMyContract
{
public double Division(double x, double y)
{
throw new DivideByZeroException("除数不能为零啦!");
}
}
寄宿服务
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(MyContract));
host.AddServiceEndpoint(typeof(IMyContract), new WSHttpBinding(), "http://localhost:8010");
host.Opened += delegate { Console.WriteLine("服务已经开启!"); };
host.Open();
Console.ReadLine();
}
}
客户端
static void Main(string[] args)
{
ChannelFactory<Host.IMyContract > channel = new ChannelFactory<Host.IMyContract >();
channel.Endpoint.Binding = new WSHttpBinding();
channel.Endpoint.Address = new EndpointAddress("http://localhost:8010");
Host.IMyContract client = channel.CreateChannel();
try
{
client.Division(1, 2);
}
catch (DivideByZeroException ex)
{
Console.WriteLine("我是DivideByZeroException错误!我的错误信息是:{0}", ex.Message);
}
catch (FaultException ex)
{
Console.WriteLine("我是FaultException错误!");
}
Console.ReadLine();
}
运行效果如下:
图1
从运行效果上我们可以发现,虽然我们在服务端抛出了DivideByZeroException异常,但在端客户却不能被DivideByZeroException捕捉,而是被FaultException捕捉了,这是因为在WCF中,如果直接抛出异常而不定义错误契约的话,客户端是不会知道错误的具体类型的,为了使客户端与服务器解耦,所有直接抛出的错误都以FaultException到达客户端。
那么要怎么才能让客户端明确的知道服务端抛出的异常呢?这就需要用到错误契约了,也就是在定义契约的时候,我们就需要定义在实现该契约的方法中会抛出什么样的异常。定义错误契约很简单,只需要在方法的上面加上FaultContract属性即可,如下代码:
[ServiceContract]
public interface IMyContract
{
[OperationContract]
[FaultContract(typeof(DivideByZeroException))]
double Division(double x, double y);
}
我们可以为一个方法定义多个错误
,但如果有定义了错误,就必须在后面的实现中抛出这样的错误。注意,定了IsOneWay=true的方法是不能够定义错误契约的,如果一个方法同时定义了IsOneWay=true与错误契约,就会在运行时提示InvalidOperateionException异常。因为很简单,IsOneWay=true就定义了该方法为单向操作,不需要等待服务端的响应,然后却又定义返回的错误类型,这本就是矛盾的。
然后在服务的Division方法中抛出DivideByZeroException异常,如下:
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class MyContract : IMyContract
{
public double Division(double x, double y)
{
throw new FaultException<DivideByZeroException >(new DivideByZeroException("除数不能为零啦!"));
}
}
注意,上面我们不是直接抛出DivideByZeroException异常了,而是使用了FaultException<T >。
客户端也稍作修改如下:
……
try
{
client.Division(1, 2);
}
catch (FaultException<DivideByZeroException > ex)
{
Console.WriteLine("我是DivideByZeroException错误!我的错误信息是:{0}", ex.Detail.Message);
}
catch (FaultException ex)
{
Console.WriteLine("我是FaultException错误!");
}
……
运行,效果如下:
图2
从上图的效果可以看到,客户端有正确的捕获到服务端抛出的错误了。