关键时刻,一个wcf服务怎么能离得开异常处理呢?
1、 基于ServiceDebug的Exception Handling
我们把“<serviceDebug includeExceptionDetailInFaults="true"/>”设置为true以后,在WcfContract添加一个方法TradDivideOperation,在MyWcfLib类库中做除法的具体实现的时候,让它抛出DivideByZeroException异常:
Code
public double TradDivideOperation(double x, double y)
{
//在被除数为0的时候,抛出DivideByZeroException
if (y == 0)
{
throw new DivideByZeroException("divide by zero");
}
return x / y;
}在客户端我们调用的时候,try catch一下就可以捕获这个DivideByZeroException异常了。
Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using MyClient.WebHostService;//通过web方式调用服务
using MyWcfException;
namespace MyClient
{
class Program
{
static void Main(string[] args)
{
WebHostService.GetDataServiceClient webClient = new WebHostService.GetDataServiceClient();
//基于ServiceDebug的Exception Handling(只在本地调试时使用,部署时不推荐)
try
{
double result = webClient.TradDivideOperation(123.0, 0);
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine("An Exception is thrown.\n\tException Type:{0}\n\tError Message:{1}", ex.GetType(), ex.Message);
//写异常日志
}
Console.WriteLine("----------------------------------");
Console.ReadKey();
}
}
}
注意:可以看到我们我们Catch的是一个FaultException< ExceptionDetail>Type的Exception,不是原来的FaultException。该Exception的Detail属性就是Service抛出的DivideByZeroException异常。而且我们在Service端指定的Error Message也被客户端获得。这种方式的Exception Handling方式确实比上面一种具有很强的指示性,对我们进行Debug确实很有帮助。但是这种方式确实不能正式用于我们最终发布的版本中,因为它会把Exception所有的信息返回到Client端,很容易泄露一些很敏感的信息。这也正是WCF把这个列入ServiceDebug Service Behavior的原因。
2、 基于Fault Contract 的Exception Handling
我们知道,wcf采用一种基于Contract的通信方式,Contract定义了进行交互的双方进行消息交换所遵循的准则和规范,ServiceContract定义了包含了所有Operation的Service的接口,DataContract定义了交互的数据的结构,而 FaultContract实际上定义需要再双方之间进行交互的了异常、错误的表示。
下面我们现在来看看如何来使用基于FaultContract的Exception Handling。
a、首先我们改进第一篇的demo,在解决方案里添加一个类库MyWcfException,专门生成wcf的异常处理。
在该工程下,我们添加一个类
Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
namespace MyWcfException
{
[DataContract]
public class CommonError
{
private string _operation;
private string _errorMessage;
public CommonError(string operation, string errorMessage)
{
this._operation = operation;
this._errorMessage = errorMessage;
}
[DataMember]
public string Operation
{
get { return _operation; }
set { _operation = value; }
}
[DataMember]
public string ErrorMessage
{
get { return _errorMessage; }
set { _errorMessage = value; }
}
}
}
(1)、在WCF中,我们一般用两个不同的Serializer实现Object和XML的Serialization和Deserialization:Datacontract Serializer和XML Serializer。
(2)、在CommonError中定义了两个成员:表示出错操作的Operation和出错信息的ErrorMessage。由于该类的对象需要在Endpoint之间传递,所以必须是可序列化的。这里对于Fault而言,只能使用Datacontract Serializer进行序列化和反序列化。
b、在接口方法中运用FaultContract
Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using MyWcfException;
namespace WcfContract
{
[ServiceContract]
public interface IGetDataService
{
[OperationContract]
[FaultContract(typeof(CommonError))]
string GetData(string value);
[OperationContract]
double TradDivideOperation(double x, double y);
[OperationContract]
[FaultContract(typeof(CommonError))]
double DivideOperation(double x, double y);
}
}
说明: 我们在DivideOperation上运用了FaultContract,并指定了封装了Fault对应的类型,那么最终这个基于CommonError类型的FaultContract会被写入Service Description中,MyClient通过获取该Service Description(一般是获取WSDL),它就被识别它,就会将从接收到的Soap中对该Fault的XML Mapping到具体的MathError类型。
c、客户端调用异常显示
Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using MyClient.WebHostService;//通过web方式调用服务
using MyWcfException;
namespace MyClient
{
class Program
{
static void Main(string[] args)
{
WebHostService.GetDataServiceClient webClient = new WebHostService.GetDataServiceClient();
//基于Fault Contract 的Exception Handling
try
{
double result = webClient.DivideOperation(123.0, 0);
Console.WriteLine(result);
}
catch (FaultException<CommonError> ex) //异常处理
{
CommonError error = ex.Detail;
Console.WriteLine("An Fault is thrown.\n\tFault code:{0}\n\tFault Reason:{1}\n\tOperation:{2}\n\tMessage:{3}", ex.Code, ex.Reason, error.Operation, error.ErrorMessage);
//写异常日志
}
catch (Exception ex)
{
Console.WriteLine("An Exception is thrown.\n\tException Type:{0}\n\tError Message:{1}", ex.GetType(), ex.Message);
//写异常日志
}
Console.WriteLine("----------------------------------");
Console.ReadKey();
}
}
}
好了,wcf异常处理就介绍到这里。其实有前两篇文章做铺垫,简单的wcf应用已经几乎没有问题了。在这个简单wcf应用程序中,涵盖了契约、绑定、异常处理和宿主等方面的内容,网上有很多写的很精彩的资料,读者可自行参考。当然,wcf是庞大无比的一个框架,想要熟练掌握还看个人努力和修行。这里暂时搁笔,有时间再来深入学习。
1、 基于ServiceDebug的Exception Handling
我们把“<serviceDebug includeExceptionDetailInFaults="true"/>”设置为true以后,在WcfContract添加一个方法TradDivideOperation,在MyWcfLib类库中做除法的具体实现的时候,让它抛出DivideByZeroException异常:
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
public double TradDivideOperation(double x, double y)
{
//在被除数为0的时候,抛出DivideByZeroException
if (y == 0)
{
throw new DivideByZeroException("divide by zero");
}
return x / y;
}
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using MyClient.WebHostService;//通过web方式调用服务
using MyWcfException;
namespace MyClient
{
class Program
{
static void Main(string[] args)
{
WebHostService.GetDataServiceClient webClient = new WebHostService.GetDataServiceClient();
//基于ServiceDebug的Exception Handling(只在本地调试时使用,部署时不推荐)
try
{
double result = webClient.TradDivideOperation(123.0, 0);
Console.WriteLine(result);
}
catch (Exception ex)
{
Console.WriteLine("An Exception is thrown.\n\tException Type:{0}\n\tError Message:{1}", ex.GetType(), ex.Message);
//写异常日志
}
Console.WriteLine("----------------------------------");
Console.ReadKey();
}
}
}
2、 基于Fault Contract 的Exception Handling
我们知道,wcf采用一种基于Contract的通信方式,Contract定义了进行交互的双方进行消息交换所遵循的准则和规范,ServiceContract定义了包含了所有Operation的Service的接口,DataContract定义了交互的数据的结构,而 FaultContract实际上定义需要再双方之间进行交互的了异常、错误的表示。
下面我们现在来看看如何来使用基于FaultContract的Exception Handling。
a、首先我们改进第一篇的demo,在解决方案里添加一个类库MyWcfException,专门生成wcf的异常处理。
在该工程下,我们添加一个类
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
namespace MyWcfException
{
[DataContract]
public class CommonError
{
private string _operation;
private string _errorMessage;
public CommonError(string operation, string errorMessage)
{
this._operation = operation;
this._errorMessage = errorMessage;
}
[DataMember]
public string Operation
{
get { return _operation; }
set { _operation = value; }
}
[DataMember]
public string ErrorMessage
{
get { return _errorMessage; }
set { _errorMessage = value; }
}
}
}
(2)、在CommonError中定义了两个成员:表示出错操作的Operation和出错信息的ErrorMessage。由于该类的对象需要在Endpoint之间传递,所以必须是可序列化的。这里对于Fault而言,只能使用Datacontract Serializer进行序列化和反序列化。
b、在接口方法中运用FaultContract
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using MyWcfException;
namespace WcfContract
{
[ServiceContract]
public interface IGetDataService
{
[OperationContract]
[FaultContract(typeof(CommonError))]
string GetData(string value);
[OperationContract]
double TradDivideOperation(double x, double y);
[OperationContract]
[FaultContract(typeof(CommonError))]
double DivideOperation(double x, double y);
}
}
c、客户端调用异常显示
![ContractedBlock.gif](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![ExpandedBlockStart.gif](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using MyClient.WebHostService;//通过web方式调用服务
using MyWcfException;
namespace MyClient
{
class Program
{
static void Main(string[] args)
{
WebHostService.GetDataServiceClient webClient = new WebHostService.GetDataServiceClient();
//基于Fault Contract 的Exception Handling
try
{
double result = webClient.DivideOperation(123.0, 0);
Console.WriteLine(result);
}
catch (FaultException<CommonError> ex) //异常处理
{
CommonError error = ex.Detail;
Console.WriteLine("An Fault is thrown.\n\tFault code:{0}\n\tFault Reason:{1}\n\tOperation:{2}\n\tMessage:{3}", ex.Code, ex.Reason, error.Operation, error.ErrorMessage);
//写异常日志
}
catch (Exception ex)
{
Console.WriteLine("An Exception is thrown.\n\tException Type:{0}\n\tError Message:{1}", ex.GetType(), ex.Message);
//写异常日志
}
Console.WriteLine("----------------------------------");
Console.ReadKey();
}
}
}
Demo下载: WcfStudyDemo