【WCF--初入江湖】06 WCF契约服务行为和异常处理

时间:2022-02-02 19:54:32

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(, );
client.Abort();
client.Divide(, );
}
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 = )]
public string Message { get; set; }
/// <summary>
/// Gets or sets the full message of the fault data.
/// </summary>
[DataMember(Order = )]
public string FullMessage { get; set; }
/// <summary>
/// Gets or sets the stack trace information of the fault exception.
/// </summary>
[DataMember(Order = )]
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);