[WCF编程]6.绑定行为

时间:2024-01-03 11:19:56

一、绑定行为概述

为了支持服务端的其它本地特性,WCF定义了行为的概念。行为就是服务的本地特性,不会影响服务的通信模式。客户端并不知道服务端行为,所以行为不会出现在服务的绑定和发布的元数据中。说下WCF下“契约(Contract)”和“行为(Behavior)”的区别:契约是涉及双边的描述(契约是服务的提供者和服务消费者进行交互的手段),那么行为就是基于单边的描述。客户端行为体现的是WCF如何进行服务调用的方式,而服务端行为则体现了WCF的请求分发方式。所以服务契约会通过元数据对外发布,而WCF服务行为则对于客户端是透明的。

通过将行为应用于系统的各个不同部分,可以控制WCF的会话管理、并发性、限流(Throttling)和事务等活动,其中一些活动只能应用在某个级别上,如服务级别,终结点级别、操作级别和契约级别。

针对不同的级别,可以用不同的方法设置行为。大多数行为可以通过配置或配置中的特性进行设置。尽管大多数行为都可以通过配置参数来进行设置,但有些行为必须在代码中进行设置。

二、服务行为

通过[ServiceBehavior]特性,可以在服务级别上应用规则和行为。在设计时,可以利用以下属性来控制行为的并发性、实例化、限流、事务、会话和线程等:

  • AddressFilterMode:允许修改消息过滤器。AddressFilterMode属性有三个值:Any(WCF会关闭基于地址的消息筛选机制,它允许路由服务处理携带的目标地址(WS-Addressing的<To>报头,适用于消息路由)与本终结点不一致的请求消息)、Exact(指示对传入消息的地址执行精确匹配的筛选器)、Prefix(指示对传入消息的地址执行最长前缀匹配的筛选器),默认值为Exact。
  • AutomaticSessionShutdown:AutomaticSessionShutdown默认为true,当客户端关闭代理时,会话会被终止。将其设置为false,则会话会继续直到服务显式地关闭其发送通道,这样就可以控制会话的生命周期了。
  • ConcurrencyMode:用此参数可以设置服务是以单线程还是多线程运行。默认值是Single。将它设置为Multiple,则意味着在服务中必须实现线程安全。
  • IgnoreExtensionDataObject:此参数是一个布尔值,默认为false。将它设置为true,则意味着消息中不带任何未知的序列化数据。
  • IncludeExceptionDetailInFaults:如果需要把未处理的异常作为SOAP消息发送给客户端,就需要把此消息参数设置为true。在开发环境中,需要将此参数设置为true;在生产环境,需要将它设为false。
  • InstanceContextMode:用此属性可以设置服务实例的生命周期。它的值可以取PerCall(新的 System.ServiceModel.InstanceContext 对象在每次调用前创建,在调用后回收)、PerSession(为每个会话创建一个新的 System.ServiceModel.InstanceContext 对象)、Single(只有一个 System.ServiceModel.InstanceContext 对象用于所有传入呼叫,并且在调用后不回收。如果服务对象不存在,则创建一个),默认为PerSession。关于实力管理的详细信息,在后续会讲到。
  • MaxItemsInObjectGraph:此属性用来设置允许在序列化和反序列化的对象图中出现的最大项数。
  • ReleaseServiceInstanceOnTransactionComplete:如果把此参数设置为true,则表示当前活动事务结束后释放服务对象。
  • TransactionAutoCompleteOnSessionClose:如果希望在会话被客户端正常关闭时,把当前活动事务标志为结束,就需要将此参数设置为true。
  • TransactionIsolationLevel:当事务出于活动状态时,指定当前对象的隔离级别。Chaos(无法覆盖隔离级别更高的事务中的挂起的更改)、ReadCommitted(可以在事务期间读取可变数据,但是不可以修改它)、ReadUncommitted(可以在事务期间读取和修改可变数据)、RepeatableRead(可以在事务期间读取可变数据,但是不可以修改。可以在事务期间添加新数据)、Serializable(可以在事务期间读取可变数据,但是不可以修改,也不可以添加任何新数据)、Snapshot(可以读取可变数据。在事务修改数据之前,它验证在它最初读取数据之后另一个事务是否更改过这些数据。 如果数据已被更新,则会引发错误。 这样使事务可获取先前提交的数据值)、Unspecified(正在使用与指定隔离级别不同的隔离级别,但是无法确定该级别。 如果设置了此值,则会引发异常)。
  • TransactionTimeout:设置事务的超时时间,超过此时间之后,此事务即被认为已经中止,回滚过程被激活。
  • UseSynchronizationContext:该值指定是否使用当前同步上下文来选择执行的线程
  • ValidateMustUnderstand:此属性用来关闭对标志为MustUnderstand的SOAP头的验证。默认为true。

三、操作行为

利用OperationBehavior特性控制类的方法,利用类的方法可以进一步控制服务的某些方面。在操作级别可以控制的行为有事务行为、访问者身份识别行为和对象回收行为。

  • AutoDisposeParameters:此属性允许操作自动释放输入、输出和引用参数。默认为false。
  • Impersonation:有时需要以访问者的身份执行操作。为了满足这种需求,需要把这个属性设置为Required或Allowed。
  • ReleaseInstanceMode:此属性允许覆盖当前服务对象的 InstanceContextMode回收值。可能的取值有None(根据 InstanceContextMode 值回收对象)、BeforeCall(在调用操作前回收对象)、AfterCall(在完成操作后回收对象)、BeforeAndAfterCall(在调用操作前和完成操作后回收对象)。默认值为None。
  • TransactionAutoComplete:当事务启动时,如果当前方法没有产生错误,则这个属性会把当前事务标志为结束,否则放弃此事务。当这个属性设置为false时,必须手工把事务标志为结束或放弃。
  • TransactionScopeRequired:通过此属性可判断一个事务是否是当前方法所请求的。

利用OperationBehavior特性,可以控制与服务操作有密切关系的参数。只需把此特性应用于需要管理的操作上,然后根据具体需要设置行为的属性参数,就可以得到所需要的行为,代码如下所示:

[OperationBehavior(AutoDisposeParameters=true,
Impersonation=ImpersonationOption.NotAllowed,
ReleaseInstanceMode=ReleaseInstanceMode.None,
TransactionAutoComplete=true,
TransactionScopeRequired=false)]
public void SayOneWay(string str)
{
Console.WriteLine(str);
}

上面这个示例中,OperationBehavior特性的全部属性都取的是默认值。

四、终结点行为

虽然服务行为只在服务端有用,但是终结点行为既可以应用于所有服务,也可以应用于客户端。给终结点设置适合的行为可以实现对客户端证书的使用的序列化器参数的管理。WCF提供了一组预先定义好的行为,其中每个行为都可以实现System.ServiceModel.Description.IEndpointBehavior接口:

  • AddBindingParameters:用此行为检查当前服务描述并可以根据终结点行为的需要修改绑定参数,此方法对每个终结点只能调用一次。
  • ApplyDispatchBehavior:IEndpointBehavior接口最重要的方法,可以通过它将终结点的行为逻辑应用于服务端。
  • Validate:此方法用来检查服务描述,当服务描述无法满足终结点行为需要时就抛出一个异常。

可以通过配置文件、编程或两者结合的方式,来设置各种on个不同的终结点行为。不同于服务行为,终结点行为既可以用在客户端,也可以用在服务端。有些特殊实现只允许应用于客户端,比如ClientCredential行为。

利用配置文件,可以定义并配置终结点的行为。例如在客户端,如果希望在调用相关终结点时必须提供证书,就可以使用ClientCredential行为,如下代码所示:客户端配置文件

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IHelloWorldService" />
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8000/HelloWorldService" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IHelloWorldService" contract="IHelloWorldService"
name="WSHttpBinding_IHelloWorldService" behaviorConfiguration="carRentalEndpointBehavior">
<identity>
<userPrincipalName value="网\001" />
</identity> </endpoint> </client>
<behaviors>
<endpointBehaviors>
<behavior name="carRentalEndpointBehavior">
<clientCredentials>
<clientCertificate findValue="CN=client_cert" storeLocation="CurrentUser" storeName="My" x509FindType="FindBySubjectDistinguishedName" />
</clientCredentials>
</behavior>
</endpointBehaviors>

</behaviors>
</system.serviceModel>
</configuration>

证书安全可以参见:WCF使用X509证书,证书安全后续会有介绍,这里不过多介绍。

五、契约行为

通过实现System.ServiceModel.Description.IContractBehavior接口可以扩展或修改契约的各个方面,这种方法适合于契约的整个周期。该接口有4个方法,他们都可以用于契约的修改。遇有不能在配置文件中使用契约行为,因此只能在代码中或者通过属性修改契约行为。System.ServiceModel.Description.IContractBehavior接口的4个方法如下:

  • AddBindingParameters:此方法允许添加自定义参数,这些参数常用于控制行为的执行。此方法对于每个终结点来说只能执行一次。
  • ApplyClientBehavior:可以使用这个方法在客户端应用行为逻辑。
  • ApplyDispatchBehavior:可以使用这个方法在服务客户端应用行为逻辑。
  • Validate:用于验证行为执行时的运行时上下文。

对于IEndpointBehavior,IContractBehavior既可以应用于契约接口的客户端,也可以应用于契约接口的服务端 。然而,一个IContractBehavior实现却不能在运行时通过配置文件进行修改,只能在设计时通过属性或编程方法进行添加。

[DeliveryRequirements(
QueuedDeliveryRequirements=QueuedDeliveryRequirementsMode.NotAllowed,
RequireOrderedDelivery=true)]
public class HelloWorldService : IHelloWorldService
{
// }

在上述示例中,DeliveryRequirements表示契约不是按序列发送,而是要求消息按顺序发送。

参考书籍:《WCF 4 高级编程》