通过行为配置和扩展运行时

行为使你能够修改默认行为,并添加自定义扩展,用于检查和验证服务配置或修改 Windows Communication Foundation(WCF) 客户端和服务应用程序中的运行时行为。 本主题介绍行为接口、如何实现它们,以及如何以编程方式或配置文件将其添加到服务说明(在服务应用程序)或终结点(在客户端应用程序中)。 有关使用系统提供的行为的详细信息,请参阅 指定服务 Run-Time 行为指定客户端 Run-Time 行为

行为

在 Windows Communication Foundation(WCF)使用这些对象创建执行 WCF 服务服务或 WCF 客户端的运行时之前,行为类型将分别添加到服务或服务终结点描述对象中。 当这些行为在运行时构造过程中被调用时,它们就能够访问可修改由协定、绑定和地址构建的运行时的属性和方法。

行为方法

所有行为都有一个 AddBindingParameters 方法、一个 ApplyDispatchBehavior 方法、一个 Validate 方法和一个 ApplyClientBehavior 方法,但有一个例外:由于 IServiceBehavior 无法在客户端中执行,因此它不实现 ApplyClientBehavior

  • 使用AddBindingParameters 方法修改或添加自定义对象到一个集合,供自定义绑定在构建运行时时访问和使用。 例如,如何指定保护要求,这些要求会影响通道的生成方式,但通道开发人员并不了解。

  • 使用该方法 Validate 检查说明树和相应的运行时对象,以确保它符合一组条件。

  • 使用ApplyDispatchBehaviorApplyClientBehavior方法来检查描述树,并对服务或客户端上特定范围的运行时进行修改。 还可以插入扩展对象。

    注释

    虽然这些方法中提供了说明树,但它仅用于检查。 如果修改了说明树,则行为未定义。

可以通过服务和客户端运行时类访问可以修改的属性和可以实现的自定义接口。 服务类型是 DispatchRuntimeDispatchOperation 类。 客户端类型为 ClientRuntimeClientOperation 类。 这些 ClientRuntimeDispatchRuntime 类是用于分别访问客户端范围和服务范围的运行时属性和扩展集合的扩展性入口点。 同样,ClientOperation 类和 DispatchOperation 类分别公开客户端操作和服务操作的运行时属性及扩展集合。 但是,如果需要,可以从操作运行时对象访问作用域更广的运行时对象,反之亦然。

注释

有关可用于修改客户端执行行为的运行时属性和扩展类型的讨论,请参阅 扩展客户端。 有关可用于修改服务调度程序执行行为的运行时属性和扩展类型的讨论,请参阅 扩展调度程序

大多数 WCF 用户不直接与运行时交互;而是使用核心编程模型构造,例如终结点、协定、绑定、地址和配置文件中的类或行为属性。 这些构造构成了 描述树,这是用于构造运行时以支持描述树描述的服务或客户端的完整规范。

WCF 中有四种类型的行为:

可以通过实现自定义属性、使用应用程序配置文件或直接将它们添加到相应描述对象的行为集合,将这些行为添加到各种描述对象。 但在对 ICommunicationObject.OpenServiceHost 调用 ChannelFactory<TChannel> 之前,必须将这些行为添加到服务说明或服务终结点说明对象。

行为范围

有四种行为类型,每个类型对应于特定的运行时访问范围。

服务行为

服务行为实现 IServiceBehavior,它是赖以修改整个服务运行时的主要机制。 有三种机制可用于向服务添加服务行为。

  1. 在服务类上使用属性。 构造 a ServiceHost 时, ServiceHost 实现使用反射来发现服务类型的属性集。 如果这些属性中的任何一个是 IServiceBehavior 的实现,那么它们会被添加到 ServiceDescription 的行为集合中。 这样可以让这些行为参与到服务运行时的构建中。

  2. 以编程方式将行为添加到 ServiceDescription 上的行为集合中。 这可以通过以下代码行来实现:

    ServiceHost host = new ServiceHost(/* Parameters */);  
    host.Description.Behaviors.Add(/* Service Behavior */);  
    
  3. 实现用于扩展配置的自定义 BehaviorExtensionElement。 这允许使用应用程序配置文件中的服务行为。

WCF 中的服务行为示例包括 ServiceBehaviorAttribute 属性、ServiceThrottlingBehavior 行为和 ServiceMetadataBehavior 行为。

合同行为

协定行为实现 IContractBehavior 接口,它用于在协定范围内扩展客户端和服务运行时。

有两种机制可用于向协定添加协定行为。 第一种机制是在协定接口上创建自定义属性。 当契约接口传递给 ServiceHostChannelFactory<TChannel> 时,WCF 将检查该接口上的属性。 如果有任何属性是实现的 IContractBehavior,这些属性将添加到为该接口创建的行为集合 System.ServiceModel.Description.ContractDescription 中。

还可以将 System.ServiceModel.Description.IContractBehaviorAttribute 应用于自定义协定行为属性。 在这种情况下,在应用于以下情况时,行为如下所示:

• 协定接口。 在这种情况下,该行为将应用于任何终结点中该类型的所有协定,WCF 将忽略该属性的值 IContractBehaviorAttribute.TargetContract

• 服务类。 在这种情况下,该行为仅应用于合同的终结点,该合同的属性值为 TargetContract

• 回调类。 在此情况下,该行为将应用到双工客户端的终结点,并且 WCF 会忽略 TargetContract 属性的值。

第二种方式是将该行为添加到 ContractDescription 上的行为集合中。

WCF 中的协定行为示例包括 System.ServiceModel.DeliveryRequirementsAttribute 属性。 有关详细信息和示例,请参阅参考主题。

终结点行为

实现的 IEndpointBehavior终结点行为是修改特定终结点的整个服务或客户端运行时的主要机制。

有两种机制可用于向服务添加终结点行为。

  1. 将行为添加到 Behaviors 属性。

  2. 实现一个扩展配置功能的自定义元素 BehaviorExtensionElement

有关详细信息和示例,请参阅参考主题。

操作行为

实现 IOperationBehavior 接口的操作行为用于扩展每个操作的客户端和服务运行时。

有两种机制可用于为操作添加操作行为。 第一种机制是创建自定义属性,用于对作建模的方法。 将某个操作添加到 ServiceHostChannelFactory 时,WCF 会将任何 IOperationBehavior 属性添加到为该操作创建的 OperationDescription 的行为集合中。

第二种机制是直接将行为添加到已构建的 OperationDescription 的行为集合中。

WCF 中的作行为示例包括 OperationBehaviorAttributeTransactionFlowAttribute.

有关详细信息和示例,请参阅参考主题。

使用配置创建行为

服务和终结点以及协定行为可以设计为在代码中指定或使用属性;只能使用应用程序或 Web 配置文件配置服务和终结点行为。 使用属性公开行为允许开发人员在编译时指定在运行时无法添加、删除或修改的行为。 这通常适用于服务正确运行时始终需要的功能(例如,传递给System.ServiceModel.ServiceBehaviorAttribute属性的事务相关参数)。 使用配置公开行为允许开发人员将这些行为的规范和配置留给部署服务的人员。 这种方式适合于作为可选组件或其他特定于部署的配置的行为,比如是否为服务或服务的特定授权配置公开元数据。

注释

也可以使用支持配置的行为,并通过将这些行为插入到 machine.config 配置文件并锁定这些项来强制执行公司的应用程序策略。 有关介绍和示例,请参阅如何:在企业中锁定终结点

若要使用配置公开行为,开发人员必须创建派生类, BehaviorExtensionElement 然后将该扩展注册到配置。

以下代码示例演示如何 IEndpointBehavior 实现 BehaviorExtensionElement

// BehaviorExtensionElement members  
public override Type BehaviorType  
{  
  get { return typeof(EndpointBehaviorMessageInspector); }  
}  
  
protected override object CreateBehavior()  
{  
  return new EndpointBehaviorMessageInspector();  
}  

为了使配置系统加载自定义 BehaviorExtensionElement,必须将其注册为扩展。 下面的代码示例显示了上述终结点行为的配置文件:

<configuration>  
  <system.serviceModel>  
    <services>  
      <service
        name="Microsoft.WCF.Documentation.SampleService"  
        behaviorConfiguration="metadataSupport"  
      >  
        <host>  
          <baseAddresses>  
            <add baseAddress="http://localhost:8080/ServiceMetadata" />  
          </baseAddresses>  
        </host>  
        <endpoint  
          address="/SampleService"  
          binding="wsHttpBinding"  
          behaviorConfiguration="withMessageInspector"
          contract="Microsoft.WCF.Documentation.ISampleService"  
        />  
        <endpoint  
           address="mex"  
           binding="mexHttpBinding"  
           contract="IMetadataExchange"  
        />  
      </service>  
    </services>  
    <behaviors>  
      <serviceBehaviors>  
      <behavior name="metadataSupport">  
        <serviceMetadata httpGetEnabled="true" httpGetUrl=""/>  
      </behavior>  
      </serviceBehaviors>  
      <endpointBehaviors>  
        <behavior name="withMessageInspector">  
          <endpointMessageInspector />  
        </behavior>  
      </endpointBehaviors>  
    </behaviors>  
    <extensions>  
      <behaviorExtensions>  
        <add
          name="endpointMessageInspector"  
          type="Microsoft.WCF.Documentation.EndpointBehaviorMessageInspector, HostApplication, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"  
        />  
      </behaviorExtensions>  
    </extensions>  
  </system.serviceModel>  
</configuration>  

其中,Microsoft.WCF.Documentation.EndpointBehaviorMessageInspector 是行为扩展类型,HostApplication 是该类已编译到的程序集的名称。

评估顺序

System.ServiceModel.ChannelFactory<TChannel>System.ServiceModel.ServiceHost 负责从编程模型和说明生成运行时。 如前面所述,行为可在服务、终结点、协定和操作中参与该生成过程。

ServiceHost 按以下顺序应用行为:

  1. 服务

  2. 合约

  3. 端点

  4. 操作

在任何行为集合中,都不能保证任何顺序。

ChannelFactory<TChannel> 按以下顺序应用行为:

  1. 合约

  2. 端点

  3. 操作

在任何行为集合中,不保证有顺序。

以编程方式添加行为

服务应用程序中 System.ServiceModel.Description.ServiceDescription 的属性不能在 CommunicationObject.OnOpening 上的 System.ServiceModel.ServiceHostBase 方法之后进行修改。 某些成员(例如在 ServiceHostBase.CredentialsAddServiceEndpoint 上的ServiceHostBase 属性和 System.ServiceModel.ServiceHost 方法)如果在经过该点后被修改,会引发异常。 某些允许你修改它们,但结果是不确定的。

同样,在调用 System.ServiceModel.Description.ServiceEndpoint 上的 OnOpening 之后不能在客户端上修改 System.ServiceModel.ChannelFactory 值。 ChannelFactory.Credentials属性在超过该状态后进行修改时会引发异常,但可以无错误地修改其他客户端描述值。 但是,结果未定义。

无论是对于服务还是客户端,建议在调用 CommunicationObject.Open前修改说明。

行为属性的继承规则

可以使用属性(服务行为和协定行为)填充所有四种类型的行为。 由于属性是在托管对象和成员上定义的,并且托管对象和成员支持继承,因此有必要定义行为属性在继承上下文中的工作方式。

总体来看,规则是,对于一个特定范围(例如服务、合同或操作),应用该范围继承层次结构中的所有行为属性。 如果同一类型有两个行为属性,则仅使用最派生的类型。

服务行为

对于给定的服务类,该类及该类的父类上的所有服务行为属性均适用。 如果在继承层次结构中的多个位置应用同一类型的属性,则使用派生最多的类型。

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]  
[AspNetCompatibilityRequirementsAttribute(  
    AspNetCompatibilityRequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]  
public class A { /* … */ }  
  
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]  
public class B : A { /* … */}  

例如在上例中,服务 B 结束时,其 InstanceContextModeSingleAspNetCompatibilityRequirementsMode 模式为 AllowedConcurrencyModeSingleConcurrencyModeSingle,这是因为服务 B 上的 ServiceBehaviorAttribute 属性比服务 A 上的该属性“派生程度更高”。

合同行为

对于给定合同,将应用该接口及其父接口上的所有合同行为属性。 如果在继承层次结构中的多个位置应用同一类型的属性,则使用派生最多的类型。

操作行为

如果给定的操作不覆盖现有的抽象或虚拟操作,则不会应用任何继承规则。

如果操作重写现有操作,则该操作及该操作的父操作上的所有操作行为属性均适用。 如果在继承层次结构中的多个位置应用同一类型的属性,则使用派生最多的类型。