Configurando e estendendo o runtime com comportamentos

Os comportamentos permitem modificar o comportamento padrão e adicionar extensões personalizadas que inspecionam e validam a configuração de serviço ou modificam o comportamento de runtime em aplicativos de cliente e serviço do WCF (Windows Communication Foundation). Este tópico descreve as interfaces de comportamento, como implementá-las e como adicioná-las à descrição do serviço (em um aplicativo de serviço) ou ponto de extremidade (em um aplicativo cliente) programaticamente ou em um arquivo de configuração. Para obter mais informações sobre como usar comportamentos fornecidos pelo sistema, consulte Especificando o comportamento do Run-Time de serviço e especificando o comportamento do cliente Run-Time.

Comportamentos

Os tipos de comportamento são adicionados aos objetos de descrição do ponto de extremidade de serviço ou serviço (no serviço ou no cliente, respectivamente), antes que esses objetos sejam usados pelo WCF (Windows Communication Foundation) para criar um runtime que executa um serviço WCF ou um cliente WCF. Quando esses comportamentos são chamados durante o processo de construção do runtime, eles são capazes de acessar propriedades e métodos de runtime que modificam o runtime construído pelo contrato, associações e endereços.

Métodos de comportamento

Todos os comportamentos têm um método AddBindingParameters, um método ApplyDispatchBehavior, um método Validate e um método ApplyClientBehavior com uma exceção: como IServiceBehavior não é possível executar em um cliente, ele não implementa ApplyClientBehavior.

  • Use o método AddBindingParameters para modificar ou adicionar objetos personalizados a uma coleção que as associações personalizadas podem acessar para seu uso quando o runtime for construído. Por exemplo, é assim que os requisitos de proteção são especificados que afetam a forma como o canal é criado, mas não são conhecidos pelo desenvolvedor do canal.

  • Use o método Validate para examinar a árvore de descrição e o objeto de runtime correspondente para garantir que ele esteja em conformidade com algum conjunto de critérios.

  • Use os métodos ApplyDispatchBehavior e ApplyClientBehavior para examinar a árvore de descrição e modificar o runtime para um escopo específico no serviço ou no cliente. Você também pode inserir objetos de extensão.

    Observação

    Embora uma árvore de descrição seja fornecida nesses métodos, ela é somente para exame. Se uma árvore de descrição for modificada, o comportamento será indefinido.

As propriedades que você pode modificar e as interfaces de personalização que você pode implementar são acessadas por meio das classes de runtime do cliente e do serviço. Os tipos de serviço são as classes DispatchRuntime e DispatchOperation. Os tipos de cliente são as classes ClientRuntime e ClientOperation. As classes ClientRuntime e DispatchRuntime são os pontos de entrada de extensibilidade para acessar as propriedades de runtime e as coleções de extensões em todo o cliente e em todo o serviço, respectivamente. Da mesma forma, as classes ClientOperation e DispatchOperation expõem as propriedades de runtime de operação e de serviço do cliente e as coleções de extensões, respectivamente. No entanto, você pode acessar o objeto runtime com escopo mais amplo do objeto runtime da operação e vice-versa, se necessário.

Observação

Para uma discussão sobre propriedades de runtime e tipos de extensão que você pode usar para modificar o comportamento de execução de um cliente, consulte Estender Clientes. Para uma discussão sobre propriedades de runtime e tipos de extensão que você pode usar para modificar o comportamento de um dispatcher de serviço, consulte Estender Dispatchers.

A maioria dos usuários do WCF não interage diretamente com o runtime; em vez disso, eles usam constructos de modelo de programação principais, como pontos de extremidade, contratos, associações, endereços e atributos de comportamento em classes ou comportamentos em arquivos de configuração. Esses constructos compõem a árvore de descrição, que é a especificação completa para construir um runtime para dar suporte a um serviço ou cliente descrito pela árvore de descrição.

Existem quatro tipos de comportamentos no WCF:

Você pode adicionar esses comportamentos aos vários objetos de descrição implementando atributos personalizados, usando arquivos de configuração de aplicativo ou diretamente adicionando-os à coleção de comportamentos no objeto de descrição apropriado. No entanto, deve ser adicionado a um objeto de descrição do ponto de extremidade de serviço ou descrição do ponto de extremidade de serviço antes de chamar ICommunicationObject.Open em ServiceHost ou ChannelFactory<TChannel>.

Escopos de comportamento

Há quatro tipos de comportamento, cada um deles corresponde a um escopo específico de acesso ao runtime.

Comportamentos de Serviço

Os comportamentos de serviço, que implementam IServiceBehavior, são o mecanismo primário pelo qual você modifica todo o runtime do serviço. Há três mecanismos para adicionar comportamentos de serviço a um serviço.

  1. Usando um atributo na classe de serviço. Quando um ServiceHost é construído, a implementação ServiceHost usa reflexão para descobrir o conjunto de atributos no tipo do serviço. Se algum desses atributos for implementações de IServiceBehavior, eles serão adicionados à coleção de comportamentos em ServiceDescription. Isso permite que esses comportamentos participem da construção do tempo de execução do serviço.

  2. Adicionando programaticamente o comportamento à coleção de comportamentos em ServiceDescription. Faça isso com o seguinte comando do LocBaml:

    ServiceHost host = new ServiceHost(/* Parameters */);  
    host.Description.Behaviors.Add(/* Service Behavior */);  
    
  3. Implemente um BehaviorExtensionElement personalizado que estenda a configuração. Isso permite o uso do comportamento do serviço dos arquivos de configuração do aplicativo.

Exemplos de comportamentos de serviço no WCF incluem o atributo ServiceBehaviorAttribute, o ServiceThrottlingBehavior e o comportamento ServiceMetadataBehavior.

Comportamentos do contrato

Os comportamentos do contrato, que implementam a interface IContractBehavior, são usados para estender o runtime do cliente e do serviço em um contrato.

Há dois mecanismos para adicionar comportamentos contratuais a um contrato. O primeiro mecanismo é criar um atributo personalizado a ser usado na interface do contrato. Quando uma interface de contrato é passada para um ServiceHost ou um ChannelFactory<TChannel>, o WCF examina os atributos na interface. Se quaisquer atributos forem implementações, IContractBehavioreles serão adicionados à coleção de comportamentos em System.ServiceModel.Description.ContractDescription criada para aquela interface.

Você também pode implementar o atributo System.ServiceModel.Description.IContractBehaviorAttribute de comportamento do contrato personalizado. Nesse caso, o comportamento é o seguinte quando aplicado a:

• Uma interface de contrato. Nesse caso, o comportamento é aplicado a todos os contratos desse tipo em qualquer ponto de extremidade e o WCF ignora o valor da propriedade IContractBehaviorAttribute.TargetContract.

• Uma classe de serviço. Nesse caso, o comportamento é aplicado somente aos pontos de extremidade do contrato do qual é o valor da propriedade TargetContract.

• Uma classe de retorno de chamada. Nesse caso, o comportamento é aplicado ao endpoint do cliente duplex, e o WCF ignora o valor da propriedade TargetContract.

O segundo mecanismo é adicionar o comportamento à coleção de comportamentos em ContractDescription.

Exemplos de comportamentos de contrato no WCF incluem o atributo System.ServiceModel.DeliveryRequirementsAttribute. Para obter mais informações e um exemplo, consulte o tópico de referência.

Comportamentos de Ponto de Extremidade

Os comportamentos de ponto de extremidade, que implementam IEndpointBehavior, são o mecanismo primário pelo qual você modifica todo o tempo de execução do serviço ou do cliente para um ponto de extremidade específico.

Há dois mecanismos para adicionar comportamentos de ponto de extremidade a um serviço.

  1. Adicione o comportamento à propriedade Behaviors.

  2. Implemente um personalizado BehaviorExtensionElement que estenda a configuração.

Para obter mais informações e um exemplo, consulte o tópico de referência.

Comportamentos da operação

Os comportamentos de operação, que implementam a interface IOperationBehavior, são usados para estender o runtime do cliente e do serviço para cada operação.

Há dois mecanismos para adicionar comportamentos de operação a uma operação. O primeiro mecanismo é criar um atributo personalizado a ser usado no método que modela a operação. Quando uma operação é adicionada a um ServiceHost ou um ChannelFactory, o WCF adiciona quaisquer atributos IOperationBehavior à coleção de comportamentos em OperationDescription criado para essa operação.

O segundo mecanismo é adicionar diretamente o comportamento à coleção de comportamentos em OperationDescription construído.

Exemplos de comportamentos de operação no WCF incluem OperationBehaviorAttribute e TransactionFlowAttribute.

Para obter mais informações e um exemplo, consulte o tópico de referência.

Usando a configuração para criar comportamentos

Comportamentos de serviço e ponto de extremidade e contrato podem ser projetados para serem especificados no código ou usando atributos; somente comportamentos de serviço e ponto de extremidade podem ser configurados usando arquivos de configuração do aplicativo ou da Web. Expor comportamentos usando atributos permite que os desenvolvedores especifiquem um comportamento em tempo de compilação que não pode ser adicionado, removido ou modificado em tempo de execução. Isso geralmente é adequado para comportamentos que sempre são necessários para a operação correta de um serviço (por exemplo, os parâmetros relacionados à transação ao atributo System.ServiceModel.ServiceBehaviorAttribute). Expor comportamentos usando a configuração permite que os desenvolvedores deixem a especificação e a configuração desses comportamentos para aqueles que implantam o serviço. Isso é adequado para comportamentos que são componentes opcionais ou outra configuração específica de implantação, como se os metadados são expostos para o serviço ou a configuração de autorização específica para um serviço.

Observação

Você também pode usar comportamentos que dão suporte à configuração para impor políticas de aplicativo da empresa inserindo-as no arquivo de configuração machine.config e bloqueando esses itens. Para obter uma descrição e um exemplo, consulte Como bloquear pontos de extremidade na empresa.

Para expor um comportamento usando a configuração, um desenvolvedor deve criar uma classe derivada BehaviorExtensionElement e registrar essa extensão com a configuração.

O exemplo de código a seguir mostra como IEndpointBehavior implementa BehaviorExtensionElement:

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

Para que o sistema de configuração carregue um BehaviorExtensionElement personalizado, ele deve ser registrado como uma extensão. O exemplo de código a seguir mostra o arquivo de configuração para o comportamento do ponto de extremidade anterior:

<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>  

Em que Microsoft.WCF.Documentation.EndpointBehaviorMessageInspector é o tipo de extensão de comportamento, e HostApplication é o nome do assembly no qual essa classe foi compilada.

Ordem de avaliação

System.ServiceModel.ChannelFactory<TChannel> e System.ServiceModel.ServiceHost são responsáveis por criar o runtime com base no modelo de programação e da descrição. Os comportamentos, conforme descrito anteriormente, contribuem para esse processo de build no serviço, ponto de extremidade, contrato e operação.

ServiceHost aplica comportamentos na seguinte ordem:

  1. Serviço

  2. Contrato

  3. Ponto de extremidade

  4. Operação

Em qualquer coleção de comportamentos, nenhuma ordem é garantida.

Os comportamentos ChannelFactory<TChannel> são aplicados na seguinte ordem:

  1. Contrato

  2. Ponto de extremidade

  3. Operação

Em qualquer coleção de comportamentos, novamente, nenhuma ordem é garantida.

Adicionando comportamentos programaticamente

As propriedades de System.ServiceModel.Description.ServiceDescription do aplicativo de serviço não devem ser modificadas posteriormente para o método CommunicationObject.OnOpening em System.ServiceModel.ServiceHostBase. Alguns membros, como a propriedade ServiceHostBase.Credentials e os métodos AddServiceEndpoint em ServiceHostBase e System.ServiceModel.ServiceHost, lançam uma exceção se modificados além desse ponto. Outros permitem modificá-los, mas o resultado é indefinido.

Da mesma forma, no cliente, os valores System.ServiceModel.Description.ServiceEndpoint não devem ser modificados após a chamada para OnOpening no System.ServiceModel.ChannelFactory. A propriedade ChannelFactory.Credentials gera uma exceção se modificada após esse ponto, mas os outros valores de descrição do cliente podem ser modificados sem erro. O resultado, no entanto, é indefinido.

Seja para o serviço ou cliente, é recomendável modificar a descrição antes de chamar CommunicationObject.Open.

Regras de herança para atributos de comportamento

Todos os quatro tipos de comportamentos podem ser preenchidos usando atributos – comportamentos de serviço e comportamentos de contrato. Como os atributos são definidos em objetos e membros gerenciados e os objetos gerenciados e os membros dão suporte à herança, é necessário definir como os atributos de comportamento funcionam no contexto da herança.

Em um alto nível, a regra é que, para um escopo específico (por exemplo, serviço, contrato ou operação), todos os atributos de comportamento na hierarquia de herança para esse escopo são aplicados. Se houver dois atributos de comportamento do mesmo tipo, somente o tipo mais derivado será usado.

Comportamentos de Serviço

Para uma determinada classe de serviço, todos os atributos de comportamento de serviço nessa classe, e os pais dessa classe são aplicados. Se o mesmo tipo de atributo for aplicado em vários locais na hierarquia de herança, o tipo mais derivado será usado.

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

Por exemplo, no caso anterior, o serviço B acaba com um InstanceContextMode de Single, um modo AspNetCompatibilityRequirementsMode de Allowed, e um ConcurrencyMode de Single. O ConcurrencyMode é Single, porque o atributo ServiceBehaviorAttribute no serviço B está em "mais derivado" do que no serviço A.

Comportamentos do contrato

Para um determinado contrato, todos os atributos de comportamento do contrato nessa interface e nos pais dessa interface são aplicados. Se o mesmo tipo de atributo for aplicado em vários locais na hierarquia de herança, o tipo mais derivado será usado.

Comportamentos da operação

Se uma determinada operação não substituir uma operação abstrata ou virtual existente, nenhuma regra de herança se aplicará.

Se uma operação substituir uma operação existente, todos os atributos de comportamento de operação nessa operação e os pais dessa operação serão aplicados. Se o mesmo tipo de atributo for aplicado em vários locais na hierarquia de herança, o tipo mais derivado será usado.