(四)、WCF契约编程

 

  1. 契约类型:
  2. 服务契约(Service Contract)定义了客户端执行的服务操作
  3. 数据契约(Data Contract)定义了与服务交互的数据类型
  4. 消息契约(Message Contract) 允许服务直接与消息交换
  5. 错误契约(Fault Contract)定义了服务抛出的错误

2. 服务契约:

    2.1  服务契约和WSDL: 服务契约和WSDL转化

    ServiceContract --> wsdl:service

    OperationContract --> wsdl:operation

    2.2 服务契约的重载问题

    WCF不能使用重载,但使用OperationContractName可以解决。

     using System; using System.ServiceModel; namespace WCF.Third { [ServiceContract] public interface IService { //设置Name属性解决重载问题 [OperationContract(Name="HelloString")] String Hello(String input); [OperationContract(Name = "HelloVoid")] void Hello(); } /// <summary> /// 服务契约的实现 /// </summary> public class Service : IService { public String Hello(String input) { return "Hello, " + input; } public void Hello() { Console.WriteLine("Hello"); } } }

    2.3 定义请求-响应操作

    同步和异步操作。大部分绑定都是请求响应操作。只有使用MSMQ协议和P2P协议不支持请求——响应操作

    2.4 定义单程操作(One Way)不需要服务端给出响应

    // Server 端 using System; using System.ServiceModel; using System.Threading; namespace WCF.Third { [ServiceContract] public interface IService { //单程操作 [OperationContract(IsOneWay=true)] void OneWay(); //请求响应操作 [OperationContract] void RequestReply(); } /// <summary> /// 服务契约的实现 /// </summary> public class Service : IService { public void OneWay() { //阻止当前线程10秒 Thread.Sleep(10 * 1000); } public void RequestReply() { //阻止当前线程10秒 Thread.Sleep(10 * 1000); } } } // Host using System; using System.ServiceModel; using System.ServiceModel.Channels; namespace WCF.Third { class Host { static void Main(string[] args) { using (ServiceHost host = new ServiceHost(typeof(Service))) { host.Open(); Console.Read(); } } } } // Clinet端 using System; using System.ServiceModel; using System.ServiceModel.Channels; namespace WCF.Third { class Client { /// <summary> /// 入口方法 /// </summary> static void Main(string[] args) { using (ClientProxy proxy = new ClientProxy()) { Console.WriteLine("{0} 开始调用请求响应操作。", DateTime.Now.ToLongTimeString()); proxy.RequestReply(); Console.WriteLine("{0} 结束调用请求响操作。", DateTime.Now.ToLongTimeString()); Console.WriteLine("{0} 开始调用单程操作。", DateTime.Now.ToLongTimeString()); proxy.OneWay(); Console.WriteLine("{0} 结束调用单程操作。", DateTime.Now.ToLongTimeString()); } Console.Read(); } } //[ServiceContract] //public interface IService //{ // //单程操作 // [OperationContract(IsOneWay = true)] // void OneWay(); // //请求响应操作 // [OperationContract] // void RequestReply(); //} /// <summary> /// 客户端代理类型 /// </summary> class ClientProxy : ClientBase<IService>, IService { //硬编码定义绑定 public static readonly Binding HelloWorldBinding = new WSHttpBinding(); //硬编码定义地址 public static readonly EndpointAddress HelloWorldAddress = new EndpointAddress(new Uri("http://localhost:8675/Service")); /// <summary> /// 构造方法 /// </summary> public ClientProxy() : base(HelloWorldBinding, HelloWorldAddress) { } public void OneWay() { Channel.OneWay(); } public void RequestReply() { Channel.RequestReply(); } } }   

    2.5 定义双程操作:使得服务端可以回调客户端操作,而不需要在客户端实现,寄宿新的服务契约

    2.5.1  定义:允许客户端向服务端发出调用,而服务端也可向客户端发出调用,所有也称为回调操作

    2.5.2 双程操作的服务端设置:其核心内容是定义回调契约,在WCF中使用ServiceContractCallbackContract属性定义一个回调契约。

    2.5.3 双程操作的客户端设置:需要公开回调总结点以供服务端进行回调。

    2.5.4 双程操作的死锁问题

    回调动作会引发死锁:

  1. 默认情况下,服务端被配置为单线程访问。当 服务类型执行时,该对象被锁。
  2. 服务回调客户端操作时,当前线程被阻止,但锁未被释放。
  3. 当回调操作完成时,客户端发送返回消息,这时候需要争用服务端服务对象的锁。
  4. 这时候服务对象仍处于等待中,并且占据锁,死锁产生。
  5. 三种解决方法:

  6. 设置回调操作为单程操作,这样客户端的回调操作完成后,不需要发送返回信息。也就不会产生死锁。
  7. 设置服务的并发行为为多线程。这样多个线程访问对象,而不产生争用情况。但由于设置了多线程,服务的实现必须考虑特殊资源的同步问题。
  8. 设置服务的并发行为为可重入。这种情况下,服务对象仍只允许单线程访问。但服务端回调客户端操作时,WCF释放对象锁,这样就不会产生争用(不理解)
  9. 2.5.5 实例:

     //Server端 using System; using System.ServiceModel; using System.ServiceModel.Channels; namespace WCF.Third { /// <summary> /// 回调契约 /// </summary> public interface IHeartbeatCallback { /// <summary> /// 回调操作,调整心跳频率 /// </summary> /// <param name="seconds">新的频率</param> [OperationContract(IsOneWay=true)] void UpdateInterval(int seconds); } /// <summary> /// 心跳服务契约 /// </summary> [ServiceContract(CallbackContract = typeof(IHeartbeatCallback))] public interface IHeartbeatService { [OperationContract] void Heartbeat(); } /// <summary> /// 契约实现 /// </summary> [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)] public class HeartbeatService : IHeartbeatService { //是否处于高负荷状态 private bool _highLoad = false; //状态是否已经改变 private bool _changed = false; //不同负荷下的心跳周期 private int _highloadInterval = 5; private int _lowloadInterval = 2; //设置负荷状态 public bool HighLoad { set { lock (this) { if (_highLoad != value) { _changed = true; _highLoad = value; Console.WriteLine("Highload 已经被设置为:{0}", value); } } } } //实现心跳契约 public void Heartbeat() { //如何符合已经更改,则回调客户端,更新心跳频率 if (_changed) { IHeartbeatCallback callback = OperationContext.Current.GetCallbackChannel<IHeartbeatCallback>(); callback.UpdateInterval(_highLoad ? _highloadInterval : _lowloadInterval); } Console.WriteLine("{0} 收到心跳。",DateTime.Now.ToString()); } } } // Host using System; using System.ServiceModel; namespace WCF.Third { /// <summary> /// 寄宿程序 /// </summary> class Host { static void Main(string[] args) { try { //为了能否访问服务对象,这里手动创建服务对象并以该对象创建寄宿对象。 HeartbeatService instance = new HeartbeatService(); using (ServiceHost host = new ServiceHost(instance)) { //打开服务 host.Open(); Console.WriteLine("服务已经启动。"); //这里供用户在Console窗体中输入命令 while (true) { char command = Convert.ToChar(Console.Read()); switch (command) { //输入q表示退出程序 case 'q': return; //输入h表示切换到高负荷 case 'h': { //通过ServiceHost的SingletonInstance属性来获得寄宿实例 HeartbeatService service = (HeartbeatService)host.SingletonInstance; if (service != null) service.HighLoad = true; break; } //输入l表示切换到低负荷 case 'l': { HeartbeatService service = (HeartbeatService)host.SingletonInstance; if (service != null) service.HighLoad = false; break; } default: break; } } } } catch (Exception ex) { Console.WriteLine(ex.ToString()); Console.Read(); } } } } // Client端 using System; using System.ServiceModel; using System.Threading; using System.ServiceModel.Channels; namespace WCF.Third { public class MainClass { static void Main(string[] args) { try { //得到回调实例 Client client = new Client(); //创建代理 using (HeartbeatProxy proxy = new HeartbeatProxy(new InstanceContext(client), new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/HeartbeatService"))) { //循环发送心跳 while(true) { proxy.Heartbeat(); Thread.Sleep(client.Interval); } } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } finally { Console.Read(); } } } /// <summary> /// 回调契约的实现 /// </summary> public class Client:IHeartbeatCallback { private TimeSpan _interval = TimeSpan.FromSeconds(2); public TimeSpan Interval { get { return _interval; } } //更新心跳频率 public void UpdateInterval(int seconds) { lock (this) { _interval = TimeSpan.FromSeconds(seconds); } } } /// <summary> /// 回调契约 /// </summary> public interface IHeartbeatCallback { [OperationContract(IsOneWay=true)] void UpdateInterval(int seconds); } /// <summary> /// 服务契约 /// </summary> [ServiceContract(CallbackContract = typeof(IHeartbeatCallback))] public interface IHeartbeatService { [OperationContract] void Heartbeat(); } /// <summary> /// 客户端代理的实现 /// </summary> public class HeartbeatProxy : DuplexClientBase<IHeartbeatService>, IHeartbeatService { public HeartbeatProxy(InstanceContext context, Binding binding, EndpointAddress remoteAddress) : base(context, binding, remoteAddress) { } public void Heartbeat() { Channel.Heartbeat(); } } }

    2.6  WCF 中事件的实现。 WCF中,事件的实现机制要依靠双程操作。一般而言,客户端通过调用服务端的方法来订阅时间,而服务端通过回调来触发事件,为了保存客户端订阅事件的回调引用,可以用委托链来保存每个事件的回调引用。

    // 服务端 using System; using System.ServiceModel; using System.ServiceModel.Channels; namespace WCF.Third { /// <summary> /// 事件类型的定义 /// </summary> public enum EventType { Event1 = 1, Event2 = 2, Event3 = 3 } /// <summary> /// 回调契约,实现了事件的触发 /// </summary> public interface IEvents { //事件1的触发操作 [OperationContract(IsOneWay = true)] void OnEvent1(); //事件2的触发操作 [OperationContract(IsOneWay = true)] void OnEvent2(int arg); //事件3的触发操作 [OperationContract(IsOneWay = true)] void OnEvent3(String arg); } [ServiceContract(CallbackContract=typeof(IEvents))] public interface IEventPublisher { //订阅事件的操作 [OperationContract] void Subscribe(EventType events); //取消订阅事件的操作 [OperationContract] void Unsubscribe(EventType events); //触发事件 void OnEvent(EventType eve, params object[] Args); } // 契约实现 // <summary> /// 存储回调引用的泛型委托定义 /// </summary> public delegate void GenericEventHandler(); public delegate void GenericEventHandler<T>(T arg); /// <summary> /// 事件发布服务的实现 /// </summary> [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)] public class EventPublisher:IEventPublisher { //存储回调引用的泛型委托链实例 static GenericEventHandler event1List; static GenericEventHandler<int> event2List; static GenericEventHandler<String> event3List; /// <summary> /// 订阅事件的实现 /// </summary> /// <param name="events">订阅的事件</param> public void Subscribe(EventType events) { //得到回调引用 IEvents subscriber = OperationContext.Current.GetCallbackChannel<IEvents>(); //查看订阅的是哪些事件,并把回调引用存储到相应的委托链中 if ((events & EventType.Event1) == EventType.Event1) event1List += subscriber.OnEvent1; if ((events & EventType.Event2) == EventType.Event2) event2List += subscriber.OnEvent2; if ((events & EventType.Event3) == EventType.Event3) event3List += subscriber.OnEvent3; } /// <summary> /// 取消事件的订阅 /// </summary> /// <param name="events">事件</param> public void Unsubscribe(EventType events) { //得到回调引用 IEvents subscriber = OperationContext.Current.GetCallbackChannel<IEvents>(); //查看取消的是哪些事件,并从相应的委托链中移除引用 if ((events & EventType.Event1) == EventType.Event1) event1List -= subscriber.OnEvent1; if ((events & EventType.Event2) == EventType.Event2) event2List -= subscriber.OnEvent2; if ((events & EventType.Event3) == EventType.Event3) event3List -= subscriber.OnEvent3; } /// <summary> /// 事件触发方法 /// </summary> /// <param name="eve">事件</param> /// <param name="Args">参数</param> public void OnEvent(EventType eve,params object[] Args) { if (eve == EventType.Event1 && event1List!=null) event1List(); else if (eve == EventType.Event2 && event2List != null) event2List((int)Args[0]); else if (eve == EventType.Event3 && event3List != null) event3List((String)Args[0]); } } } // Host using System; using System.ServiceModel; namespace WCF.Third { /// <summary> /// 寄宿程序 /// </summary> class Host { static void Main(string[] args) { try { //为了能否访问服务对象,这里手动创建服务对象并以该对象创建寄宿对象。 EventPublisher instance = new EventPublisher(); using (ServiceHost host = new ServiceHost(instance)) { //打开服务 host.Open(); Console.WriteLine("服务已经启动。"); //这里供用户在Console窗体中输入命令 while (true) { char command = Convert.ToChar(Console.Read()); switch (command) { //输入q表示退出程序 case 'q': return; case '1': { //通过ServiceHost的SingletonInstance属性来获得寄宿实例 EventPublisher service = (EventPublisher)host.SingletonInstance; if (service != null) service.OnEvent(EventType.Event1); break; } case '2': { //通过ServiceHost的SingletonInstance属性来获得寄宿实例 EventPublisher service = (EventPublisher)host.SingletonInstance; if (service != null) service.OnEvent(EventType.Event2,0); break; } case '3': { //通过ServiceHost的SingletonInstance属性来获得寄宿实例 EventPublisher service = (EventPublisher)host.SingletonInstance; if (service != null) service.OnEvent(EventType.Event3,"a"); break; } default: break; } } } } catch (Exception ex) { Console.WriteLine(ex.ToString()); Console.Read(); } } } } // Client端 using System; using System.ServiceModel; using System.ServiceModel.Channels; namespace WCF.Third { /// <summary> /// 事件类型的定义 /// </summary> public enum EventType { Event1 = 1, Event2 = 2, Event3 = 3 } /// <summary> /// 回调契约,实现了事件的触发 /// </summary> public interface IEvents { //事件1的触发操作 [OperationContract(IsOneWay = true)] void OnEvent1(); //事件2的触发操作 [OperationContract(IsOneWay = true)] void OnEvent2(int arg); //事件3的触发操作 [OperationContract(IsOneWay = true)] void OnEvent3(String arg); } [ServiceContract(CallbackContract = typeof(IEvents))] public interface IEventPublisher { //订阅事件的操作 [OperationContract] void Subscribe(EventType events); //取消订阅事件的操作 [OperationContract] void Unsubscribe(EventType events); } // 契约实现 using System; using System.ServiceModel; using System.Threading; using System.ServiceModel.Channels; namespace WCF.Third { public class MainClass { static void Main(string[] args) { try { EventHandler handler = new EventHandler(); using (MyProxy proxy = new MyProxy(new InstanceContext(handler), new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/EventService"))) { while (true) { String command = Console.ReadLine(); switch (command) { //输入q表示退出程序 case "q": return; case "s1": { proxy.Subscribe(EventType.Event1); break; } case "s2": { proxy.Subscribe(EventType.Event2); break; } case "s3": { proxy.Subscribe(EventType.Event3); break; } case "s12": { proxy.Subscribe(EventType.Event1|EventType.Event2); break; } case "s13": { proxy.Subscribe(EventType.Event1 | EventType.Event3); break; } case "s23": { proxy.Subscribe(EventType.Event3 | EventType.Event2); break; } case "s123": { proxy.Subscribe(EventType.Event1 | EventType.Event2 | EventType.Event3); break; } case "u1": { proxy.Unsubscribe(EventType.Event1); break; } case "u2": { proxy.Unsubscribe(EventType.Event2); break; } case "u3": { proxy.Unsubscribe(EventType.Event3); break; } case "u12": { proxy.Unsubscribe(EventType.Event1 | EventType.Event2); break; } case "u13": { proxy.Unsubscribe(EventType.Event1 | EventType.Event3); break; } case "u23": { proxy.Unsubscribe(EventType.Event3 | EventType.Event2); break; } case "u123": { proxy.Unsubscribe(EventType.Event1 | EventType.Event2 | EventType.Event3); break; } default: break; } } } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } finally { Console.Read(); } } } /// <summary> /// 回调契约的实现 /// </summary> public class EventHandler:IEvents { public void OnEvent1() { Console.WriteLine("事件1触发。"); } public void OnEvent2(int arg) { Console.WriteLine("事件2触发,参数:{0}。", arg); } public void OnEvent3(String arg) { Console.WriteLine("事件3触发,参数:{0}。", arg); } } /// <summary> /// 客户端代理的实现 /// </summary> public class MyProxy : DuplexClientBase<IEventPublisher>, IEventPublisher { public MyProxy(InstanceContext context, Binding binding, EndpointAddress remoteAddress) : base(context, binding, remoteAddress) { } public void Subscribe(EventType events) { Channel.Subscribe(events); } public void Unsubscribe(EventType events) { Channel.Unsubscribe(events); } } } }

3.数据契约

 

  • 类型名、成员名、成员类型:可以使用Name属性定义类型在XSD中的别名。
  • 序列化顺序相等:

 

    3.1 数据契约和XSD

    数据契约需要转化成跨平台的数据定义,所使用的就是XSD

    3.2 使用DataContract特性定义数据契约

    使用DataContract特性而不使用传统的Serializable特性的目的之一,就是精确的指定哪些成员需要在服务器中实现。DataContractDataMember不受publicprivate可访问修饰符的限制。

    3.3 数据契约的继承

    WCF支持数据类型的继承,但父类和子类必须都属于数据契约。

     using System; using System.ServiceModel; using System.Runtime.Serialization; namespace WCF.Third { /// <summary> /// 基类 /// </summary> [DataContract] public class BaseClass { [DataMember] public String Name; [DataMember] public int Age; } /// <summary> /// 子类 /// </summary> [DataContract] public class SonClass:BaseClass { [DataMember] public String Description; } /// <summary> /// 服务契约 /// </summary> [ServiceContract] public interface IService { [OperationContract] void DoSomeWork(SonClass obj); } /// <summary> /// 实现服务契约 /// </summary> public class Service:IService { public void DoSomeWork(SonClass obj) { Console.WriteLine("姓名是:{0}", obj.Name); Console.WriteLine("年龄是:{0}", obj.Age.ToString()); Console.WriteLine("备注是:{0}", obj.Description); } } }

    3.4 已知类型的定义:就是强行的将数据类型放入到服务的元数据中。

    3.4.1 使用KnowType特性在数据类型上声明,用于声明数据契约所知的类型。通常情况下指的是该类型的所有被服务使用到的子类。

    [DataContract] [KnownType(typeof(B))] //定义B为A的已知类型 class A { [DataMember] public string a; } [DataContract] class B : A //继承A { [DataMember] public string b; }

    3.4.2 使用ServiceKnownType特性定义已知类型。和KnownType不同的是,该特性被声明在服务契约或者特定的操作契约上。这样声明的范围更小,更灵活。

    [DataContract] class A { [DataMember] public string a; } [DataContract] class B : A //继承A { [DataMember] public string b; } /// <summary> /// 服务契约 /// </summary> [ServiceContract] public interface IService { [OperationContract] [ServiceKnownType(typeof(B))] void DoSomeWork(A a); }

       3.4.3 在接口上使用已知类型

    public interface IA { string GetString { get; } } public class B : IA { public string GetString { get { return "B"; } } } [ServiceContract] [ServiceKnownType(typeof(B))] public interface IService { [OperationContract] void DoSomeWork(IA a); [OperationContract] IA GetResult(); }

    3.5 数据契约的等效性

    所谓等效的数据契约是指数据契约具有相同的传输表述形式。主要有以下两点要素:

    A 如果是继承,则基类数据成员排在第一位

    B 排在下一位的当前类型的数据成员(按字母顺序)

    C 设置DataMemberAttribute特性的Order属性的任何成员

    3.6 数据契约的版本控制

    3.6.1 新增成员,WCF对新增成员的策略是丢失新增字段。

    3.6.2 缺失成员, WCF对缺失的成员赋值为0null

    3.7 定义必须的数据成员。

    用DataMember的特性IsRequied属性定义必须的数据成员。

    3.8 数据默认值的发生

    DataMemberEmitDefaultValue属性设为false,避免发生默认值传送

    3.9 数组和集合的处理

    3.9.1 对数组作为一种类型处理

    3.9.2 集合 定义了CollectionDataContract 特性

    using System; using System.ServiceModel; using System.Runtime.Serialization; using System.Collections.Generic; using System.Collections; namespace WCF.Third { /// <summary> /// 定义集合数据契约 /// </summary> [CollectionDataContract] public class LogCollection<T> : IEnumerable<T> { private List<T> _logs = new List<T>(); IEnumerator IEnumerable.GetEnumerator() { return _logs.GetEnumerator(); } IEnumerator<T> IEnumerable<T>.GetEnumerator() { return _logs.GetEnumerator(); } public void Add(T item) { _logs.Add(item); } } /// <summary> /// 定义简单的服务契约 /// </summary> [ServiceContract] public interface IService { [OperationContract] void PrintLogs(LogCollection<String> logs); } /// <summary> /// 服务契约的实现 /// </summary> public class Service : IService { /// <summary> /// 打印所有的log /// </summary> /// <param name="logs"></param> public void PrintLogs(LogCollection<String> logs) { foreach (String log in logs) Console.WriteLine(log); } } }

4. 消息契约

    如果想要定制SOAP消息的HeadBody内容,就需要用到消息契约

    4.1 基本概念

    消息 契约给予程序员直接访问SOAP消息的HeadBody部分的能力

    4.2 强类型消息

    使用MessageContract特性来声明,一旦声明了MessageContract,类型可以作为SOAP消息发送或接受

     using System; using System.ServiceModel; using System.Runtime.Serialization; namespace WCF.Third { /// <summary> /// SOAP的头部类型 /// </summary> [Serializable] public class HeaderInfo { //会话ID public int SessionId; //描述 public String Description; public HeaderInfo(int id, String des) { SessionId = id; Description = des; } } /// <summary> /// SOAP的Body类型 /// </summary> [Serializable] public class BodyInfo { //类型信息 public String Type; //时间信息 public DateTime Time; //日志内容 public String Content; public BodyInfo(String type, DateTime time, String content) { Type = type; Time = time; Content = content; } } /// <summary> /// 接受的消息契约 /// </summary> [MessageContract] public class LogMessage { [MessageHeader] public HeaderInfo headerInfo; [MessageBodyMember] public BodyInfo bodyInfo; public LogMessage(HeaderInfo header, BodyInfo body) { headerInfo = header; bodyInfo = body; } /// <summary> /// 消息契约必须包含默认构造方法,否在在反序列化时将产生异常 /// </summary> public LogMessage() { } } /// <summary> /// 返回码 /// </summary> public enum ResponseCode { Success=101, Fail=102 } /// <summary> /// 返回的消息契约 /// </summary> [MessageContract] public class ResponseMessage { [MessageHeader] public ResponseCode responseCode; [MessageBodyMember] public String Response; public ResponseMessage(ResponseCode code, String response) { responseCode = code; Response = response; } } }

    4.3 弱类型消息

    利用Message作为消息契约

5.错误处理和错误契约

    5.1 SOAP消息的错误处理

    异常被放在SOAP body里的Fault节点上。

    5.2 服务端未捕获的异常: FalutException SOAPfault节点直接对应

    5.3 包含详细信息的异常:解决未捕获的异常丢失的问题就是使用ServiceDebugBehaviorIncludeExceptionDetailInFaults属性

    using System; using System.ServiceModel; namespace WCF.Third { [ServiceContract] public interface IService { [OperationContract] void ThrowException(); } [ServiceBehavior(IncludeExceptionDetailInFaults = false)] public class Service : IService { /// <summary> /// 抛出异常 /// </summary> public void ThrowException() { throw new NullReferenceException("测试异常"); } } }

    5.4 捕获服务异常,如果未捕获异常,将会导通信结束

    using System; using System.ServiceModel; namespace WCF.Third { [ServiceContract] public interface IService { [OperationContract] void ThrowException(String type); } [ServiceBehavior(IncludeExceptionDetailInFaults = true)] public class Service : IService { /// <summary> /// 抛出异常 /// </summary> public void ThrowException(String type) { try { //根据type的值抛出不同类型的异常 switch (type) { case "Null": { throw new NullReferenceException("测试空引用异常"); break; } case "Normal": { throw new Exception("测试普通异常"); break; } } } catch (NullReferenceException ex) { //重新抛出FaultException throw new FaultException(ex.Message); } catch (Exception ex) { //重新抛出FaultException throw new FaultException(ex.Message); } } } }

    5.5 FaultCodeFaultReason的使用

    5.5.1 FaultCode的设置,分为三类:

  1. Sender
  2. Receiver
  3. 自定义
  4. 5.5.2 FalutReason的设置

    using System; using System.ServiceModel; namespace WCF.Third { [ServiceContract] public interface IService { [OperationContract] void ThrowException(String type); } [ServiceBehavior(IncludeExceptionDetailInFaults = true)] public class Service : IService { /// <summary> /// 抛出异常 /// </summary> public void ThrowException(String type) { //根据type的值抛出不同类型的异常 switch (type) { case "Null": { //设置FaultCode和FaultReason FaultCode faultCode = FaultCode.CreateSenderFaultCode(new FaultCode("空引用")); FaultReasonText[] reasons = new FaultReasonText[2]{ new FaultReasonText("NullReferenceException"), new FaultReasonText("测试空引用异常")}; throw new FaultException(new FaultReason(reasons), faultCode); break; } case "Normal": { //设置FaultCode和FaultReason FaultCode faultCode = FaultCode.CreateReceiverFaultCode(new FaultCode("普通异常")); FaultReasonText[] reasons = new FaultReasonText[2]{ new FaultReasonText("Exception"), new FaultReasonText("测试普通异常")}; throw new FaultException(new FaultReason(reasons), faultCode); break; } } } } }

    5.6 使用错误契约和FaultException<T>

    using System; using System.ServiceModel; using System.Runtime.Serialization; namespace WCF.Third { [ServiceContract] public interface IService { [OperationContract] [FaultContract(typeof(NullReferenceException))] [FaultContract(typeof(Exception))] [FaultContract(typeof(MyException))] void ThrowException(String type); } [ServiceBehavior(IncludeExceptionDetailInFaults = true)] public class Service : IService { /// <summary> /// 抛出异常 /// </summary> public void ThrowException(String type) { //根据type的值抛出不同类型的异常 switch (type) { case "Null": { //设置FaultCode和FaultReason FaultCode faultCode = FaultCode.CreateSenderFaultCode(new FaultCode("空引用")); FaultReasonText[] reasons = new FaultReasonText[2]{ new FaultReasonText("NullReferenceException"), new FaultReasonText("测试空引用异常")}; //生成FaultException<NullReferenceException> throw new FaultException<NullReferenceException>(new NullReferenceException("测试空引用异常"), new FaultReason(reasons), faultCode); } case "Normal": { //设置FaultCode和FaultReason FaultCode faultCode = FaultCode.CreateReceiverFaultCode(new FaultCode("普通异常")); FaultReasonText[] reasons = new FaultReasonText[2]{ new FaultReasonText("Exception"), new FaultReasonText("测试普通异常")}; //生成FaultException<Exception> throw new FaultException<Exception>(new Exception("测试普通异常"), new FaultReason(reasons), faultCode); } case "Customized": { String message = "自定义异常"; throw new FaultException<MyException>(new MyException(message)); } } } } /// <summary> /// 作为FaultException<T>的实参,所以使用了DataContract和DataMember /// </summary> [DataContract] public class MyException { [DataMember] public String Message; public MyException(String message) { Message = message; } } }

     

    代码示例下载

     

     

你可能感兴趣的:(编程,exception,String,Class,interface,WCF)