Partilhar via


Como: Usar filtros

Este tópico descreve as etapas básicas necessárias para criar uma configuração de roteamento que usa vários filtros. Neste exemplo, as mensagens são roteadas para duas implementações de um serviço de calculadora, regularCalc e roundingCalc. Ambas as implementações suportam as mesmas operações; no entanto, um serviço arredonda todos os cálculos para o valor inteiro mais próximo antes de retornar. Um aplicativo cliente deve ser capaz de indicar se deve usar a versão de arredondamento do serviço; Se nenhuma preferência de serviço for expressa, a mensagem terá balanceamento de carga entre os dois serviços. As operações expostas por ambos os serviços são:

  • Adicionar

  • Subtract

  • Multiplicar

  • Dividir

Como ambos os serviços implementam as mesmas operações, não é possível usar o filtro Ação, porque a ação especificada na mensagem não será exclusiva. Em vez disso, você deve fazer trabalho adicional para garantir que as mensagens sejam roteadas para os pontos de extremidade apropriados.

Determinar dados exclusivos

  1. Como ambas as implementações de serviço lidam com as mesmas operações e são essencialmente idênticas, além dos dados que retornam, os dados básicos contidos nas mensagens enviadas de aplicativos cliente não são exclusivos o suficiente para permitir que você determine como rotear a solicitação. Mas se o aplicativo cliente adicionar um valor de cabeçalho exclusivo à mensagem, você poderá usar esse valor para determinar como a mensagem deve ser roteada.

    Neste exemplo, se o aplicativo cliente precisar que a mensagem seja processada pela calculadora de arredondamento, ele adicionará um cabeçalho personalizado usando o seguinte código:

    messageHeadersElement.Add(MessageHeader.CreateHeader("RoundingCalculator",
                                   "http://my.custom.namespace/", "rounding"));  
    

    Agora você pode usar o filtro XPath para inspecionar mensagens para esse cabeçalho e rotear mensagens contendo o cabeçalho para o serviço roundCalc.

  2. Além disso, o Serviço de Roteamento expõe dois pontos de extremidade de serviço virtual que podem ser usados com os filtros EndpointName, EndpointAddress ou PrefixEndpointAddress para rotear exclusivamente as mensagens de entrada para uma implementação de calculadora específica com base no ponto de extremidade para o qual o aplicativo cliente envia a solicitação.

Definir Endpoints

  1. Ao definir os pontos de extremidade usados pelo Serviço de Roteamento, você deve primeiro determinar a forma do canal usado por seus clientes e serviços. Nesse cenário, ambos os serviços de destino usam um padrão de solicitação-resposta, portanto, o IRequestReplyRouter é usado. O exemplo a seguir define os pontos de extremidade de serviço expostos pelo Serviço de Roteamento.

    <services>  
          <service behaviorConfiguration="routingConfiguration"  
                   name="System.ServiceModel.Routing.RoutingService">  
            <host>  
              <baseAddresses>  
                <add baseAddress="http://localhost/routingservice/router" />  
              </baseAddresses>  
            </host>  
            <!--Set up the inbound endpoints for the Routing Service-->  
            <!--first create the general router endpoint-->  
            <endpoint address="general"  
                      binding="wsHttpBinding"  
                      name="routerEndpoint"  
                      contract="System.ServiceModel.Routing.IRequestReplyRouter" />  
            <!--create a virtual endpoint for the regular calculator service-->  
            <endpoint address="regular/calculator"  
                      binding="wsHttpBinding"  
                      name="calculatorEndpoint"  
                      contract="System.ServiceModel.Routing.IRequestReplyRouter" />  
            <!--now create a virtual endpoint for the rounding calculator-->  
            <endpoint address="rounding/calculator"  
                      binding="wsHttpBinding"  
                      name="roundingEndpoint"  
                      contract="System.ServiceModel.Routing.IRequestReplyRouter" />  
    
          </service>  
    </services>  
    

    Com essa configuração, o Serviço de Roteamento expõe três pontos de extremidade separados. Dependendo das opções de tempo de execução, o aplicativo cliente envia mensagens para um desses endereços. As mensagens que chegam a um dos pontos finais do serviço "virtual" ("arredondamento/calculadora" ou "regular/calculadora") são encaminhadas para a implementação da calculadora correspondente. Se o aplicativo cliente não enviar a solicitação para um ponto de extremidade específico, a mensagem será endereçada ao ponto de extremidade geral. Independentemente do ponto de extremidade escolhido, o aplicativo cliente também pode optar por incluir o cabeçalho personalizado para indicar que a mensagem deve ser encaminhada para a implementação da calculadora de arredondamento.

  2. O exemplo a seguir define os pontos de extremidade do cliente (destino) para os quais o Serviço de Roteamento roteia mensagens.

    <client>  
          <endpoint name="regularCalcEndpoint"  
                    address="net.tcp://localhost:9090/servicemodelsamples/service/"  
                    binding="netTcpBinding"  
                    contract="*" />  
    
          <endpoint name="roundingCalcEndpoint"  
                    address="net.tcp://localhost:8080/servicemodelsamples/service/"  
                    binding="netTcpBinding"  
                    contract="*" />  
    </client>  
    

    Esses pontos de extremidade são usados na tabela de filtros para indicar o ponto de extremidade de destino para o qual a mensagem é enviada quando corresponde a um filtro específico.

Definir Filters

  1. Para rotear mensagens com base no cabeçalho personalizado "RoundingCalculator" que o aplicativo cliente adiciona à mensagem, defina um filtro que use uma consulta XPath para verificar a presença desse cabeçalho. Como esse cabeçalho é definido usando um namespace personalizado, adicione também uma entrada de namespace que defina um prefixo de namespace personalizado de "personalizado" que é usado na consulta XPath. O exemplo a seguir define a seção de roteamento necessária, a tabela de namespace e o filtro XPath.

    <routing>  
          <!-- use the namespace table element to define a prefix for our custom namespace-->  
          <namespaceTable>  
            <add prefix="custom" namespace="http://my.custom.namespace/"/>  
          </namespaceTable>  
          <filters>  
            <!--define the different message filters-->  
            <!--define an xpath message filter to look for the custom header coming from the client-->  
            <filter name="XPathFilter" filterType="XPath"
                    filterData="/s12:Envelope/s12:Header/custom:RoundingCalculator = 'rounding'"/>  
          </filters>  
    </routing>  
    

    Este MessageFilter procura um cabeçalho RoundingCalculator na mensagem que contém um valor de "arredondamento". Esse cabeçalho é definido pelo cliente para indicar que a mensagem deve ser roteada para o serviço roundingCalc.

    Nota

    O prefixo do namespace s12 é definido por padrão na tabela de namespace e representa o namespace http://www.w3.org/2003/05/soap-envelope.

  2. Você também deve definir filtros que procuram mensagens recebidas nos dois pontos de extremidade virtuais. O primeiro ponto de extremidade virtual é o ponto de extremidade "regular/calculadora". O cliente pode enviar solicitações para este ponto de extremidade para indicar que a mensagem deve ser roteada para o serviço regularCalc. A configuração a seguir define um filtro que usa o EndpointNameMessageFilter para determinar se a mensagem chegou por meio de um ponto de extremidade com o nome especificado em filterData.

    <!--define an endpoint name filter looking for messages that show up on the virtual regular calculator endpoint-->  
    <filter name="EndpointNameFilter" filterType="EndpointName" filterData="calculatorEndpoint"/>  
    

    Se uma mensagem for recebida pelo ponto de extremidade do serviço chamado "calculatorEndpoint", esse filtro será avaliado como true.

  3. Em seguida, defina um filtro que procure mensagens enviadas para o endereço do roundingEndpoint. O cliente pode enviar solicitações para este ponto de extremidade para indicar que a mensagem deve ser roteada para o serviço roundingCalc. A configuração a seguir define um filtro que usa o PrefixEndpointAddressMessageFilter para determinar se a mensagem chegou ao ponto de extremidade "arredondamento/calculadora".

    <!--define a filter looking for messages that show up with the address prefix.  The corresponds to the rounding calc virtual endpoint-->  
    <filter name="PrefixAddressFilter" filterType="PrefixEndpointAddress"  
            filterData="http://localhost/routingservice/router/rounding/"/>  
    

    Se uma mensagem for recebida em um endereço que começa com http://localhost/routingservice/router/rounding/ , esse filtro será avaliado como verdadeiro. Como o endereço base usado por essa configuração é http://localhost/routingservice/router e o endereço especificado para o roundingEndpoint é "arredondamento/calculadora", o endereço completo usado para se comunicar com esse ponto de extremidade é http://localhost/routingservice/router/rounding/calculator, que corresponde a esse filtro.

    Nota

    O filtro PrefixEndpointAddress não avalia o nome do host ao executar uma correspondência, porque um único host pode ser referido usando uma variedade de nomes de host que podem ser maneiras válidas de se referir ao host a partir do aplicativo cliente. Por exemplo, todos os itens a seguir podem se referir ao mesmo host:

    • localhost
    • 127.0.0.1
    • www.contoso.com
    • ContosoWeb01
  4. O filtro final deve suportar o roteamento de mensagens que chegam ao ponto de extremidade geral sem o cabeçalho personalizado. Para esse cenário, as mensagens devem alternar entre os serviços regularCalc e roundingCalc. Para dar suporte ao roteamento "round robin" dessas mensagens, use um filtro personalizado que permita que uma instância de filtro corresponda para cada mensagem processada. O seguinte define duas instâncias de um RoundRobinMessageFilter, que são agrupadas para indicar que elas devem alternar entre si.

    <!-- Set up the custom message filters.  In this example,   
         we'll use the example round robin message filter,   
         which alternates between the references-->  
    <filter name="RoundRobinFilter1" filterType="Custom"  
                    customType="CustomFilterAssembly.RoundRobinMessageFilter, CustomFilterAssembly"  
                    filterData="group1"/>  
    <filter name="RoundRobinFilter2" filterType="Custom"  
                    customType="CustomFilterAssembly.RoundRobinMessageFilter, CustomFilterAssembly"  
                    filterData="group1"/>  
    

    Durante o tempo de execução, esse tipo de filtro alterna entre todas as instâncias de filtro definidas desse tipo que são configuradas como o mesmo grupo em uma coleção. Isso faz com que as mensagens processadas por esse filtro personalizado alternem entre retornar true para RoundRobinFilter1 e RoundRobinFilter2.

Definir Filter Tables

  1. Para associar os filtros a pontos de extremidade de cliente específicos, você deve colocá-los dentro de uma tabela de filtros. Este cenário de exemplo também usa configurações de prioridade de filtro, que é uma configuração opcional que permite indicar a ordem na qual os filtros são processados. Se nenhuma prioridade de filtro for especificada, todos os filtros serão avaliados simultaneamente.

    Nota

    Embora a especificação de uma prioridade de filtro permita controlar a ordem em que os filtros são processados, isso pode afetar negativamente o desempenho do Serviço de Roteamento. Sempre que possível, construa a lógica do filtro para que o uso de prioridades de filtro não seja necessário.

    O seguinte define a tabela de filtros e adiciona o "XPathFilter" definido anteriormente à tabela com uma prioridade de 2. Esta entrada também especifica que, se a XPathFilter mensagem corresponder à mensagem, a mensagem será roteada para o roundingCalcEndpoint.

    <routing>  
    ...      <filters>  
    ...      </filters>  
          <filterTables>  
            <table name="filterTable1">  
              <entries>  
                <!--add the filters to the message filter table-->  
                <!--first look for the custom header, and if we find it,  
                    send the message to the rounding calc endpoint-->  
                <add filterName="XPathFilter" endpointName="roundingCalcEndpoint" priority="2"/>  
              </entries>  
            </table>  
          </filterTables>  
    </routing>  
    

    Ao especificar uma prioridade de filtro, os filtros de prioridade mais alta são avaliados primeiro. Se um ou mais filtros em um nível de prioridade específico corresponderem, nenhum filtro em níveis de prioridade mais baixos será avaliado. Para este cenário, 2 é a prioridade mais alta especificada e esta é a única entrada de filtro neste nível.

  2. As entradas de filtro foram definidas para verificar se uma mensagem é recebida em um ponto de extremidade específico, inspecionando o nome do ponto de extremidade ou o prefixo do endereço. As entradas a seguir adicionam ambas as entradas de filtro à tabela de filtros e as associam aos pontos de extremidade de destino para os quais a mensagem será roteada. Esses filtros são definidos como uma prioridade de 1 para indicar que eles só devem ser executados se o filtro XPath anterior não corresponder à mensagem.

    <!--if the header wasn't there, send the message based on which virtual endpoint it arrived at-->  
    <!--we determine this through the endpoint name, or through the address prefix-->  
    <add filterName="EndpointNameFilter" endpointName="regularCalcEndpoint" priority="1"/>  
    <add filterName="PrefixAddressFilter" endpointName="roundingCalcEndpoint" priority="1"/>  
    

    Como esses filtros têm uma prioridade de filtro de 1, eles só serão avaliados se o filtro no nível de prioridade 2 não corresponder à mensagem. Além disso, como ambos os filtros têm o mesmo nível de prioridade, eles serão avaliados simultaneamente. Como ambos os filtros são mutuamente exclusivos, é possível que apenas um ou outro corresponda a uma mensagem.

  3. Se uma mensagem não corresponder a nenhum dos filtros anteriores, a mensagem foi recebida através do ponto de extremidade de serviço genérico e não continha informações de cabeçalho que indicassem para onde encaminhá-la. Essas mensagens devem ser tratadas pelo filtro personalizado, que as equilibra entre os dois serviços da calculadora. O exemplo a seguir demonstra como adicionar as entradas de filtro à tabela de filtros; Cada filtro está associado a um dos dois pontos de extremidade de destino.

    <!--if none of the other filters have matched,   
        this message showed up on the default router endpoint,   
        with no custom header-->  
    <!--round robin these requests between the two services-->  
    <add filterName="RoundRobinFilter1" endpointName="regularCalcEndpoint" priority="0"/>  
    <add filterName="RoundRobinFilter2" endpointName="roundingCalcEndpoint" priority="0"/>  
    

    Como essas entradas especificam uma prioridade de 0, elas só serão avaliadas se nenhum filtro de uma prioridade mais alta corresponder à mensagem. Além disso, como ambos têm a mesma prioridade, são avaliados simultaneamente.

    Como mencionado anteriormente, o filtro personalizado usado por essas definições de filtro avalia apenas uma ou outra como true para cada mensagem recebida. Como apenas dois filtros são definidos usando esse filtro, com a mesma configuração de grupo especificado, o efeito é que o Serviço de Roteamento alterna entre o envio para o regularCalcEndpoint e o RoundingCalcEndpoint.

  4. Para avaliar as mensagens em relação aos filtros, a tabela de filtros deve primeiro ser associada aos pontos de extremidade de serviço que serão usados para receber mensagens. O exemplo a seguir demonstra como associar a tabela de roteamento aos pontos de extremidade de serviço usando o comportamento de roteamento:

    <behaviors>  
      <!--default routing service behavior definition-->  
      <serviceBehaviors>  
        <behavior name="routingConfiguration">  
          <routing filterTableName="filterTable1" />  
        </behavior>  
      </serviceBehaviors>  
    </behaviors>  
    

Exemplo

A seguir está uma lista completa do arquivo de configuração.

<?xml version="1.0" encoding="utf-8" ?>  
<!-- Copyright (c) Microsoft Corporation. All rights reserved -->  
<configuration>  
  <system.serviceModel>  
    <services>  
      <service behaviorConfiguration="routingConfiguration"  
               name="System.ServiceModel.Routing.RoutingService">  
        <host>  
          <baseAddresses>  
            <add baseAddress="http://localhost/routingservice/router" />  
          </baseAddresses>  
        </host>  
        <!--Set up the inbound endpoints for the Routing Service-->  
        <!--first create the general router endpoint-->  
        <endpoint address="general"  
                  binding="wsHttpBinding"  
                  name="routerEndpoint"  
                  contract="System.ServiceModel.Routing.IRequestReplyRouter" />  
        <!--create a virtual endpoint for the regular calculator service-->  
        <endpoint address="regular/calculator"  
                  binding="wsHttpBinding"  
                  name="calculatorEndpoint"  
                  contract="System.ServiceModel.Routing.IRequestReplyRouter" />  
        <!--now create a virtual endpoint for the rounding calculator-->  
        <endpoint address="rounding/calculator"  
                  binding="wsHttpBinding"  
                  name="roundingEndpoint"  
                  contract="System.ServiceModel.Routing.IRequestReplyRouter" />  
  
      </service>  
    </services>  
    <behaviors>  
      <!--default routing service behavior definition-->  
      <serviceBehaviors>  
        <behavior name="routingConfiguration">  
          <routing filterTableName="filterTable1" />  
        </behavior>  
      </serviceBehaviors>  
    </behaviors>  
  
    <client>  
<!--set up the destination endpoints-->  
      <endpoint name="regularCalcEndpoint"  
                address="net.tcp://localhost:9090/servicemodelsamples/service/"  
                binding="netTcpBinding"  
                contract="*" />  
  
      <endpoint name="roundingCalcEndpoint"  
                address="net.tcp://localhost:8080/servicemodelsamples/service/"  
                binding="netTcpBinding"  
                contract="*" />  
    </client>  
    <routing>  
      <!-- use the namespace table element to define a prefix for our custom namespace-->  
      <namespaceTable>  
        <add prefix="custom" namespace="http://my.custom.namespace/"/>  
      </namespaceTable>  
      <filters>  
        <!--define the different message filters-->  
        <!--define an xpath message filter to look for the custom header coming from the client-->  
        <filter name="XPathFilter" filterType="XPath" filterData="/s12:Envelope/s12:Header/custom:RoundingCalculator = 'rounding'"/>  
  
        <!--define an endpoint name filter looking for messages that show up on the virtual regular calculator endpoint-->  
        <filter name="EndpointNameFilter" filterType="EndpointName" filterData="calculatorEndpoint"/>  
  
        <!--define a filter looking for messages that show up with the address prefix.  The corresponds to the rounding calc virtual endpoint-->  
        <filter name="PrefixAddressFilter" filterType="PrefixEndpointAddress" filterData="http://localhost/routingservice/router/rounding/"/>  
  
        <!--Set up the custom message filters.  In this example, we'll use the example round robin message filter, which alternates between the references-->  
        <filter name="RoundRobinFilter1" filterType="Custom" customType="CustomFilterAssembly.RoundRobinMessageFilter, CustomFilterAssembly" filterData="group1"/>  
        <filter name="RoundRobinFilter2" filterType="Custom" customType="CustomFilterAssembly.RoundRobinMessageFilter, CustomFilterAssembly" filterData="group1"/>  
      </filters>  
      <filterTables>  
        <table name="filterTable1">  
          <entries>  
            <!--add the filters to the message filter table-->  
            <!--first look for the custom header, and if we find it, send the message to the rounding calc endpoint-->  
            <add filterName="XPathFilter" endpointName="roundingCalcEndpoint" priority="2"/>  
  
            <!--if the header wasn't there, send the message based on which virtual endpoint it arrived at-->  
            <!--we determine this through the endpoint name, or through the address prefix-->  
            <add filterName="EndpointNameFilter" endpointName="regularCalcEndpoint" priority="1"/>  
            <add filterName="PrefixAddressFilter" endpointName="roundingCalcEndpoint" priority="1"/>  
  
            <!--if none of the other filters have matched, this message showed up on the default router endpoint, with no custom header-->  
            <!--round robin these requests between the two services-->  
            <add filterName="RoundRobinFilter1" endpointName="regularCalcEndpoint" priority="0"/>  
            <add filterName="RoundRobinFilter2" endpointName="roundingCalcEndpoint" priority="0"/>  
          </entries>  
        </table>  
      </filterTables>  
    </routing>  
  </system.serviceModel>  
</configuration>  

Consulte também