WCF 学习笔记之异常处理
1:WCF异常在配置文件
<configuration> <system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="serviceDebuBehavior"> <serviceDebug includeExceptionDetailInFaults="true" /> </behavior> </serviceBehaviors> </behaviors> <services> <service name="Artech.WcfServices.Service.CalculatorService" behaviorConfiguration="serviceDebuBehavior"> <endpoint address="http://127.0.0.1:3721/calculatorservice" binding="ws2007HttpBinding" contract="Artech.WcfServices.Service.Interface.ICalculator" /> </service> </services> </system.serviceModel> </configuration>
2:也可以直接在服务上直接用特性进行设定
[ServiceBehavior(IncludeExceptionDetailInFaults=true)]
public class CalculatorService:ICalculator
{
}
上面两种方式实现的效果是一样的;
3:自定义异常信息
(1)直接通过FaultException直接指定错误的信息
using System.ServiceModel; namespace Artech.WcfServices.Service { public class CalculatorService : ICalculator { public int Divide(int x, int y) { if (0 == y) { throw new FaultException("被除数y不能为零!"); } return x / y; } } }
相应的配置文件内容为:
<configuration> <system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="serviceDebuBehavior"> <serviceDebug includeExceptionDetailInFaults="true" /> </behavior> </serviceBehaviors> </behaviors> <services> <service name="Artech.WcfServices.Service.CalculatorService" behaviorConfiguration="serviceDebuBehavior"> <endpoint address="http://127.0.0.1:3721/calculatorservice" binding="ws2007HttpBinding" contract="Artech.WcfServices.Service.Interface.ICalculator" /> </service> </services> </system.serviceModel> </configuration>
(2)通过FaultException<TDetail>采用自定义类型封装错误
首先我们看一下一个实例;注意Interface层里的CalculaltionError.cs这个是自定义封装的错误类;
CalculaltionError.cs类代码如下:它是一个数据契约
using System.Text; using System.Runtime.Serialization; namespace Artech.WcfServices.Service.Interface { [DataContract] public class CalculationError { public CalculationError(string operation, string message) { this.Operation = operation; this.Message = message; } [DataMember] public string Operation { get; set; } [DataMember] public string Message { get; set; } } }
契约里的定义如下:为了确保错误细节对象能够被正常序列化和反序列化,要按照如下的方式通过FaultContractAttribute特性为操作定义基于CalculationError类型的错误契约(错误契约的一些注意点在下面会讲到);
namespace Artech.WcfServices.Service.Interface { [ServiceContract(Namespace = "http://www.artech.com/")] public interface ICalculator { [OperationContract] [FaultContract(typeof(CalculationError))] int Divide(int x, int y); } }
服务实现里直接抛出一个FaultException<CalculationError>,并创建一个CalculationError对象作为该异常对象的细节;
using System.ServiceModel; namespace Artech.WcfServices.Service { public class CalculatorService : ICalculator { public int Divide(int x, int y) { if (0 == y) { var error = new CalculationError("Divide", "被除数y不能为零!"); throw new FaultException<CalculationError>(error, error.Message); } return x / y; } } }
服务实现的配置文件内容如下:
<configuration> <system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="serviceDebuBehavior"> <serviceDebug includeExceptionDetailInFaults="true" /> </behavior> </serviceBehaviors> </behaviors> <services> <service name="Artech.WcfServices.Service.CalculatorService" behaviorConfiguration="serviceDebuBehavior"> <endpoint address="http://127.0.0.1:3721/calculatorservice" binding="ws2007HttpBinding" contract="Artech.WcfServices.Service.Interface.ICalculator" /> </service> </services> </system.serviceModel> </configuration>
客户端调用相关的异常处理;获得FaultException<CalculationError>类型的异常
using System.ServiceModel; using Artech.WcfServices.Service.Interface; namespace Artech.WcfServices.Clients { class Program { static void Main(string[] args) { using (ChannelFactory<ICalculator> channelFactory = new ChannelFactory<ICalculator>("calculatorservice")) { ICalculator calculator = channelFactory.CreateChannel(); using (calculator as IDisposable) { try { int result = calculator.Divide(1, 0); } catch (FaultException<CalculationError> ex) { Console.WriteLine("运算错误"); Console.WriteLine("运算操作:{0}", ex.Detail.Operation); Console.WriteLine("错误消息: {0}", ex.Detail.Message); (calculator as ICommunicationObject).Abort(); } } } Console.Read(); } } }
客户端配置信息如下:
<configuration> <system.serviceModel> <client> <endpoint name="calculatorservice" address= "http://127.0.0.1:3721/calculatorservice" binding="ws2007HttpBinding" contract="Artech.WcfServices.Service.Interface.ICalculator"/> </client> </system.serviceModel> </configuration>
*接下来讲解关于错误契约的注意点:
对于错误契约的运用不仅仅在将自定义的错误细节类型应用到服务契约相应操作上时才要显式地在操作方法上应用FaultContracAttribute特性;对于一些基元类型(比如Int32, String等)也要这么做;
public class CalculatorService : ICalculator { public int Divide(int x, int y) { if (0 == y) { throw new FaultException<String>("不能为0"); } return x / y; } }
契约如下:
namespace Artech.WcfServices.Service.Interface { [ServiceContract] public interface ICalculator { [OperationContract] [FaultContract(typeof(string))] int Divide(int x, int y); } }
当然它是可以多次声明针对多个异常的处理
namespace Artech.WcfServices.Service.Interface { [ServiceContract] public interface ICalculator { [OperationContract] [FaultContract(typeof(CalculationError))] [FaultContract(typeof(string))] int Divide(int x, int y); } }
若是两个是相同类型的则要增加Name 或者Namespace来区别开;若是Name一样类型不一样同样会报错;
[ServiceContract] public interface ICalculator { [OperationContract] [FaultContract(typeof(CalculationError),Name="CalualationError")] [FaultContract(typeof(CalculationError),Name="CalualationException")] int Divide(int x, int y); }
(4)通过XmlSerializer对错误细节对象进行序列化([XmlSerializerFormat(SupportFaults=true)])因为WCF默认是采用序列化器是DataContractSerializer(WCF提供的两种序列化器DataContractSerializer 和 XmlSerializer)
[ServiceContract] public interface ICalculator { [OperationContract] [FaultContract(typeof(CalculationError))] [XmlSerializerFormat(SupportFaults=true)] int Divide(int x, int y); }
封装的错误类如下:
[Serializable] public class CalculationError { [XmlAttributeAttribute("op")] public string Operation { get; set; } [XmlElement("Error")] public string Message { get; set; } }