【WCF--初入江湖】06 WCF契约服务行为和异常处理
06 WCF契约服务行为和异常处理
一、WCF契约服务行为
【1】
服务行为可以修改和控制WCF服务的运行特性。
在实现了WCF服务契约后,可以修改服务的很多执行特性。
这些行为(或者特性)是通过配置运行时属性或者通过自定义行为来控制的。
【2】分类
WCF的行为分为两类:
服务行为(Service Behavior)
操作行为(Operation Behavior)
【3】应用的位置
应用在实现接口的类上,而不是接口上。
[ServiceBehavior] public class ServiceClass:IService1 { [OperationBehavior] public int AddNumber(int x,int y) { return x+y; }
【4】服务的行为配置有两种方式:
【4-1】使用代码配置
示例:在宿主中,使用
ServiceHost的Description.Behaviors.Add()方法
//地址 Uri pipeaddress = new Uri("net.pipe://localhost/NetNamedPipeBinding"); Uri tcpaddress = new Uri("net.tcp://localhost:8088/TcpBinding"); 。。。 //服务宿主对象 host = new ServiceHost(typeof(WcfServiceLibrary1.Service1), pipeaddress, tcpaddress); 。。。 //添加元数据 行为 ServiceMetadataBehavior mBehavior = new ServiceMetadataBehavior(); host.Description.Behaviors.Add(mBehavior);
或者是:
[ServiceBehavior] public class ServiceClass:IService1 { [OperationBehavior] public int AddNumber(int x,int y) { return x+y; } [OperationBehavior] public int SubtractNumber(int x,int y) { return x-y; } }
【4-2】使用配置文件配置
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <services> <service name="WcfServiceLibrary1.Service1" behaviorConfiguration="textBehavior"> 。。。。。。 </service> </services> <behaviors> <serviceBehaviors> <behavior name="textBehavior"> <serviceMetadata/> <serviceDebug/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
【5】[ServiceBehavior]的属性
AutomaticSessionShutdown 客户端关闭会话时服务是否自动关闭 ConcurrencyMode 线程的支持,默认:服务是单线程 IgnoreExtensionDataObject 跟序列化有关 IncludeExceptionDetaillnFaults 如何处理未被处理的异常 InstanceContextMode 服务实例对象创建的模式,PerCall 表示每次来一个请求为其创建一个对象的实例,调用后回收;PerSession是每次一个请求来只创建一个该服 务对象的实例直至其销毁,调用后进行回收,并且会话间不能共享; Single表示只允许创建一个该服务的实例,调用后不回收 ReleaseServiceInstanceOnTransactionComplete TransactionAutoCompleteOnSessionClose TransactionlsolationLevel TtansactionTimeout
AutoDisposeParameters
ReleaseInstanceMode 操作完后回收对象、调用操作前回收、根据自动方式回收
TransactionAutoComplete 使用自动提交事务,默认为true
一个配示例:
<system.serviceModel> <extensions> <behaviorExtensions> <add name="unity" type="ByteartRetail.Infrastructure.UnityExtensions.UnityBehaviorExtensionElement, ByteartRetail.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> </behaviorExtensions> </extensions> <behaviors> <serviceBehaviors> <behavior> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="false" /> <unity operationContextEnabled="true" instanceContextEnabled="true" contextChannelEnabled="true" serviceHostBaseEnabled="true" /> </behavior> </serviceBehaviors> </behaviors>
另一个:
<serviceBehaviors> <behavior name="WcfService1.Service1Behavior"> <serviceAuthorization ></serviceAuthorization> <serviceTimeouts/> <serviceThrottling maxConcurrentCalls="" maxConcurrentInstances="" maxConcurrentSessions=""/> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="false"/> </behavior> </serviceBehaviors>
二、异常处理
【1】种类:
FaultException 创建非类型化的错误,在服务端进行创建,然后用SOAP方式返回客户端
TimeoutException
CommunicationException
FaultException异常:
#region 程序集 System.ServiceModel.dll, v4.0.0.0 // C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.ServiceModel.dll #endregion using System; using System.Runtime.Serialization; using System.Security; using System.ServiceModel.Channels; namespace System.ServiceModel { // 摘要: // 用于在客户端应用程序中捕获通过协定方式指定的 SOAP 错误。 // // 类型参数: // TDetail: // 可序列化错误详细信息类型。 [Serializable] public class FaultException<TDetail> : FaultException { // 摘要: // 初始化使用指定详细信息对象的 System.ServiceModel.FaultException<TDetail> 类的新实例。 // // 参数: // detail: // 用作 SOAP 错误详细信息的对象。 public FaultException(TDetail detail); // // 摘要: // 将流反序列化为 System.ServiceModel.FaultException 对象时,使用指定的序列化信息和上下文初始化 System.ServiceModel.FaultException<TDetail> // 类的新实例。 // // 参数: // info: // 从 context 中重新构造 System.ServiceModel.FaultException 对象时必需的序列化信息。 // // context: // 从中重新构造 System.ServiceModel.FaultException 对象的流。 protected FaultException(SerializationInfo info, StreamingContext context); // // 摘要: // 初始化使用指定详细信息对象和错误原因的 System.ServiceModel.FaultException<TDetail> 类的新实例。 // // 参数: // detail: // 用作 SOAP 错误详细信息的对象。 // // reason: // SOAP 错误的原因。 public FaultException(TDetail detail, FaultReason reason); // // 摘要: // 初始化使用指定详细信息和错误原因的 System.ServiceModel.FaultException<TDetail> 类的新实例。 // // 参数: // detail: // 用作 SOAP 错误详细信息的对象。 // // reason: // SOAP 错误的原因。 public FaultException(TDetail detail, string reason); // // 摘要: // 初始化 System.ServiceModel.FaultException<TDetail> 类的新实例,该类使用指定的详细信息对象、错误原因和错误代码。 // // 参数: // detail: // 用作 SOAP 错误详细信息的对象。 // // reason: // SOAP 错误的原因。 // // code: // SOAP 错误的错误代码。 public FaultException(TDetail detail, FaultReason reason, FaultCode code); // // 摘要: // 初始化 System.ServiceModel.FaultException<TDetail> 类的新实例,该类使用指定的详细信息对象、错误原因和错误代码。 // // 参数: // detail: // 用作 SOAP 错误详细信息的对象。 // // reason: // SOAP 错误的原因。 // // code: // SOAP 错误的错误代码。 public FaultException(TDetail detail, string reason, FaultCode code); // // 摘要: // 初始化 System.ServiceModel.FaultException<TDetail> 类的新实例,该类使用指定的详细信息对象以及 SOAP // 错误原因、代码和操作值。 // // 参数: // detail: // 用作 SOAP 错误详细信息的对象。 // // reason: // SOAP 错误的原因。 // // code: // SOAP 错误的错误代码。 // // action: // SOAP 错误的操作。 public FaultException(TDetail detail, FaultReason reason, FaultCode code, string action); // // 摘要: // 初始化 System.ServiceModel.FaultException<TDetail> 类的新实例,该类使用指定的详细信息对象以及 SOAP // 错误原因、代码和操作值。 // // 参数: // detail: // 用作 SOAP 错误详细信息的对象。 // // reason: // SOAP 错误的原因。 // // code: // SOAP 错误的错误代码。 // // action: // SOAP 错误的操作。 public FaultException(TDetail detail, string reason, FaultCode code, string action); // 摘要: // 获取包含错误条件详细信息的对象。 // // 返回结果: // System.ServiceModel.FaultException<TDetail> 对象的类型参数的详细信息对象。 public TDetail Detail { get; } // 摘要: // 创建一个 System.ServiceModel.Channels.MessageFault 对象,该对象可用于创建表示 SOAP 错误的 System.ServiceModel.Channels.Message。 // // 返回结果: // 创建的错误消息。 public override MessageFault CreateMessageFault(); // // 摘要: // 实现在将对象序列化到流中时调用的 System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo,System.Runtime.Serialization.StreamingContext) // 方法。 // // 参数: // info: // 序列化时向其添加对象数据的序列化信息。 // // context: // 序列化对象的目标。 [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context); // // 摘要: // 返回 System.ServiceModel.FaultException<TDetail> 对象的字符串。 // // 返回结果: // SOAP 错误的字符串。 public override string ToString(); } }
服务端:
public class Service1 : IService1 { public void Divide(int x, int y) { try { int z = x / y; } catch(Exception e) { throw new FaultException("试图除零",new FaultCode("除法操作")); } } }
客户端:
server.Service1Client client = new wcfClient.server.Service1Client(); try { client.Divide(3, 2); client.Abort(); client.Divide(3, 0); } catch (FaultException fe) { MessageBox.Show(fe.Reason.ToString()); } catch (TimeoutException te) { MessageBox.Show("调用超时"); } catch (CommunicationException ce) { MessageBox.Show("通信异常!"); }
【2】FaultContract:自定义错误信息:FaultData
// 摘要: // 指定服务操作遇到处理错误时返回的一个或多个 SOAP 错误。 [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)] public sealed class FaultContractAttribute : Attribute
使用步骤:
第一步:
[ServiceContract(Namespace = "http://www.Keasy5.com")] public interface IOrderService { [OperationContract] [FaultContract(typeof(FaultData))] int GetShoppingCartItemCount(Guid userID);
FaultData.cs
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; using System.ServiceModel; namespace Keasy5.DataObject { /// <summary> /// Represents the data to be transferred through the /// network which contains the fault exception information. /// </summary> [DataContract] public class FaultData { #region Public Properties /// <summary> /// Gets or sets the message of the fault data. /// </summary> [DataMember(Order = 0)] public string Message { get; set; } /// <summary> /// Gets or sets the full message of the fault data. /// </summary> [DataMember(Order = 1)] public string FullMessage { get; set; } /// <summary> /// Gets or sets the stack trace information of the fault exception. /// </summary> [DataMember(Order = 2)] public string StackTrace { get; set; } #endregion #region Public Static Methods /// <summary> /// Creates a new instance of <c>FaultData</c> class from the specified <see cref="System.Exception"/> object. /// </summary> /// <param name="ex">The <see cref="System.Exception"/> object which carries the error information.</param> /// <returns>A new instance of <c>FaultData</c> class.</returns> public static FaultData CreateFromException(Exception ex) { return new FaultData { Message = ex.Message, FullMessage = ex.ToString(), StackTrace = ex.StackTrace }; } /// <summary> /// Creates a new instance of <see cref="FaultReason"/> class from the specified <see cref="Exception"/> object. /// </summary> /// <param name="ex">The <see cref="System.Exception"/> object which carries the error information.</param> /// <returns>A new instance of <see cref="FaultReason"/> class.</returns> public static FaultReason CreateFaultReason(Exception ex) { return new FaultReason(ex.Message); } #endregion } }
第二步:
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“OrderService”。 // 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 OrderService.svc 或 OrderService.svc.cs,然后开始调试。 [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)] public class OrderService : IOrderService { private readonly IOrderService orderServiceImpl = ServiceLocator.Instance.GetService<IOrderService>(); public Int32 GetShoppingCartItemCount(Guid userID) { try { return orderServiceImpl.GetShoppingCartItemCount(userID); } catch (Exception ex) { throw new FaultException<FaultData>(FaultData.CreateFromException(ex), FaultData.CreateFaultReason(ex)); } }
使用了这个构造函数:
// // 摘要: // 初始化使用指定详细信息对象和错误原因的 System.ServiceModel.FaultException<TDetail> 类的新实例。 // // 参数: // detail: // 用作 SOAP 错误详细信息的对象。 // // reason: // SOAP 错误的原因。 public FaultException(TDetail detail, FaultReason reason);