Sdílet prostřednictvím


Postupy: Používání filtrů

Toto téma popisuje základní kroky potřebné k vytvoření konfigurace směrování, která používá více filtrů. V tomto příkladu jsou zprávy směrovány na dvě implementace služby kalkulačky, regularCalc a roundingCalc. Obě implementace podporují stejné operace; ale jedna služba před vrácením zaokrouhlí všechny výpočty na nejbližší celočíselnou hodnotu. Klientská aplikace musí být schopná určit, zda se má použít zaokrouhlovací verze služby; pokud není vyjádřena žádná předvolba služby, zpráva je vyvážena mezi těmito dvěma službami. Operace vystavené oběma službami jsou:

  • Přidání

  • Subtract

  • Krát

  • Vydělit

Vzhledem k tomu, že obě služby implementují stejné operace, nelze použít filtr akce, protože akce zadaná ve zprávě nebude jedinečná. Místo toho musíte provést další práci, abyste zajistili, že se zprávy směrují do příslušných koncových bodů.

Určení jedinečných dat

  1. Vzhledem k tomu, že obě implementace služby zpracovávají stejné operace a jsou v podstatě totožné s daty, která vrací, nejsou základní data obsažená ve zprávách odeslaných z klientských aplikací dostatečně jedinečná, aby bylo možné určit, jak směrovat požadavek. Pokud ale klientská aplikace přidá do zprávy jedinečnou hodnotu záhlaví, můžete tuto hodnotu použít k určení způsobu směrování zprávy.

    V tomto příkladu, pokud klientská aplikace potřebuje zpracovat zprávu pomocí kalkulačky zaokrouhlování, přidá vlastní hlavičku pomocí následujícího kódu:

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

    Teď můžete pomocí filtru XPath zkontrolovat zprávy pro toto záhlaví a směrovat zprávy obsahující záhlaví do služby roundCalc.

  2. Kromě toho služba směrování zpřístupňuje dva koncové body virtuální služby, které je možné použít s filtry EndpointName, EndpointAddress nebo PrefixEndpointAddress pro jedinečnou směrování příchozích zpráv do konkrétní implementace kalkulačky na základě koncového bodu, do kterého klientská aplikace odešle požadavek.

Definování koncových bodů

  1. Při definování koncových bodů používaných službou směrování byste nejprve měli určit tvar kanálu používaného vašimi klienty a službami. V tomto scénáři používají cílové služby vzor odpovědi na požadavek, takže se IRequestReplyRouter použije. Následující příklad definuje koncové body služby zveřejněné službou směrování.

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

    Při této konfiguraci služba směrování zveřejňuje tři samostatné koncové body. V závislosti na volbách za běhu klientská aplikace odesílá zprávy na jednu z těchto adres. Zprávy přicházející do jednoho z "virtuálních" koncových bodů služby ("zaokrouhlování/kalkulačka" nebo "regular/calculator") se přeposílají do odpovídající implementace kalkulačky. Pokud klientská aplikace požadavek neodesílá do konkrétního koncového bodu, zpráva se adresuje obecnému koncovému bodu. Bez ohledu na zvolený koncový bod se klientská aplikace může také rozhodnout zahrnout vlastní hlavičku, která indikuje, že by zpráva měla být předána implementaci kalkulačky zaokrouhlování.

  2. Následující příklad definuje koncové body klienta (cílového), do kterého směrovací služba směruje zprávy.

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

    Tyto koncové body se v tabulce filtru používají k označení cílového koncového bodu, na který se zpráva odešle, když odpovídá určitému filtru.

Definovat filtry

  1. Chcete-li směrovat zprávy na základě vlastní hlavičky RoundingCalculator, kterou klientská aplikace přidá do zprávy, definujte filtr, který používá dotaz XPath ke kontrole přítomnosti této hlavičky. Protože je tato hlavička definována pomocí vlastního oboru názvů, přidejte také položku oboru názvů, která definuje vlastní předponu oboru názvů "vlastní", která se používá v dotazu XPath. Následující příklad definuje nezbytnou část směrování, tabulku oboru názvů a filtr 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>  
    

    Tento MessageFilter vyhledá záhlaví RoundingCalculator ve zprávě, která obsahuje hodnotu zaokrouhlování. Tato hlavička je nastavena klientem tak, aby indikovala, že zpráva by měla být směrována do služby roundingCalc.

    Poznámka:

    Předpona oboru názvů s12 je ve výchozím nastavení definována v tabulce oboru názvů a představuje obor názvů http://www.w3.org/2003/05/soap-envelope.

  2. Musíte také definovat filtry, které hledají zprávy přijaté ve dvou virtuálních koncových bodech. Prvním virtuálním koncovým bodem je koncový bod "regular/calculator". Klient může posílat žádosti do tohoto koncového bodu a indikovat, že zpráva by měla být směrována do služby RegularCalc. Následující konfigurace definuje filtr, který používá EndpointNameMessageFilter k určení, jestli zpráva přišla přes koncový bod s názvem zadaným v 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"/>  
    

    Pokud koncový bod služby přijme zprávu s názvem calculatorEndpoint, vyhodnotí se tento filtr jako true.

  3. Dále definujte filtr, který hledá zprávy odeslané na adresu zaokrouhlováníEndpointu. Klient může do tohoto koncového bodu odesílat požadavky, které indikují, že zpráva by měla být směrována do služby RoundingCalc. Následující konfigurace definuje filtr, který používá PrefixEndpointAddressMessageFilter k určení, jestli zpráva přišla do koncového bodu "zaokrouhlování/kalkulačka".

    <!--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/"/>  
    

    Pokud je zpráva přijata na adrese, která začíná http://localhost/routingservice/router/rounding/ , pak se tento filtr vyhodnotí jako true. Vzhledem k tomu, že základní adresa používaná touto konfigurací je http://localhost/routingservice/router a adresa zadaná pro zaokrouhlovací koncový bod je "zaokrouhlení/kalkulačka", úplná adresa použitá ke komunikaci s tímto koncovým bodem je http://localhost/routingservice/router/rounding/calculator, která odpovídá tomuto filtru.

    Poznámka:

    Filtr PrefixEndpointAddress nevyhodnocuje název hostitele při provádění shody, protože na jednoho hostitele lze odkazovat pomocí různých názvů hostitelů, které mohou být všechny platné způsoby odkazování na hostitele z klientské aplikace. Například všechny následující můžou odkazovat na stejného hostitele:

    • localhost
    • 127.0.0.1
    • www.contoso.com
    • ContosoWeb01
  4. Konečný filtr musí podporovat směrování zpráv, které přicházejí do obecného koncového bodu bez vlastní hlavičky. V tomto scénáři by se zprávy měly střídat mezi službami regularCalc a roundingCalc. Pokud chcete podporovat směrování "kruhového dotazování" těchto zpráv, použijte vlastní filtr, který umožňuje, aby jedna instance filtru odpovídala pro každou zpracovanou zprávu. Následující definuje dvě instance RoundRobinMessageFilter, které jsou seskupené dohromady, aby bylo uvedeno, že by se měly vzájemně střídat.

    <!-- 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"/>  
    

    Během běhu se tento typ filtru střídá mezi všemi definovanými instancemi filtru tohoto typu, které jsou nakonfigurované jako stejná skupina do jedné kolekce. To způsobí, že zprávy zpracovávané tímto vlastním filtrem se střídají mezi vrácením true a RoundRobinFilter1RoundRobinFilter2.

Definování tabulek filtru

  1. Pokud chcete filtry přidružit ke konkrétním koncovým bodům klienta, musíte je umístit do tabulky filtrů. Tento ukázkový scénář také používá nastavení priority filtru, což je volitelné nastavení, které umožňuje určit pořadí, ve kterém se filtry zpracovávají. Pokud není zadána žádná priorita filtru, vyhodnocují se všechny filtry současně.

    Poznámka:

    Při zadávání priority filtru můžete řídit pořadí, ve kterém se filtry zpracovávají, může nepříznivě ovlivnit výkon služby směrování. Pokud je to možné, vytvořte logiku filtru tak, aby použití priorit filtru nebylo vyžadováno.

    Následující tabulka definuje tabulku filtru a přidá do tabulky dříve definovaný XPathFilter s prioritou 2. Tato položka také určuje, že pokud XPathFilter odpovídá zprávě, zpráva bude směrována na 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>  
    

    Při zadávání priority filtru se filtry s nejvyšší prioritou vyhodnocují jako první. Pokud se jeden nebo více filtrů na konkrétní úrovni priority shoduje, nebudou vyhodnoceny žádné filtry na nižší úrovni priority. Pro tento scénář je zadána nejvyšší priorita 2 a jedná se o jedinou položku filtru na této úrovni.

  2. Položky filtru byly definovány a kontrolou názvu koncového bodu nebo předpony adresy zkontrolujte, jestli se v určitém koncovém bodu přijme zpráva. Následující položky přidají obě tyto položky filtru do tabulky filtru a přidruží je k cílovým koncovým bodům, na které bude zpráva směrována. Tyto filtry jsou nastaveny na prioritu 1, aby značily, že by se měly spustit pouze v případě, že předchozí filtr XPath neodpovídá zprávě.

    <!--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"/>  
    

    Protože tyto filtry mají prioritu filtru 1, vyhodnotí se pouze v případě, že filtr na úrovni priority 2 neodpovídá zprávě. Vzhledem k tomu, že oba filtry mají stejnou úroveň priority, budou vyhodnoceny současně. Vzhledem k tomu, že se oba filtry vzájemně vylučují, je možné, aby se zprávy shodovaly jenom s jedním nebo druhým.

  3. Pokud se zpráva neshoduje s žádným z předchozích filtrů, zpráva byla přijata prostřednictvím obecného koncového bodu služby a neobsáhla žádné informace hlavičky, které označují, kam se má směrovat. Tyto zprávy musí zpracovat vlastní filtr, který je vyrovnává mezi dvěma službami kalkulačky. Následující příklad ukazuje, jak přidat položky filtru do tabulky filtru; každý filtr je přidružený k jednomu ze dvou cílových koncových bodů.

    <!--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"/>  
    

    Vzhledem k tomu, že tyto položky určují prioritu 0, budou vyhodnoceny pouze v případě, že žádný filtr vyšší priority neodpovídá zprávě. Vzhledem k tomu, že obě mají stejnou prioritu, vyhodnocují se současně.

    Jak už bylo zmíněno dříve, vlastní filtr používaný těmito definicemi filtru vyhodnocuje pouze jeden nebo druhý jako true pro každou přijatou zprávu. Vzhledem k tomu, že pomocí tohoto filtru jsou definovány pouze dva filtry se stejným nastavením skupiny, je výsledkem, že služba směrování se mezi odesíláním do regularCalcEndpoint a RoundingCalcEndpoint.

  4. Pokud chcete vyhodnotit zprávy proti filtrům, musí být tabulka filtru nejprve přidružená ke koncovým bodům služby, které se použijí k příjmu zpráv. Následující příklad ukazuje, jak přidružit směrovací tabulku ke koncovým bodům služby pomocí chování směrování:

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

Příklad

Následuje úplný seznam konfiguračního souboru.

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

Viz také