Aracılığıyla paylaş


Nasıl yapılır: Hizmet Sürümü Oluşturma

Bu konuda, iletileri aynı hizmetin farklı sürümlerine yönlendiren bir yönlendirme yapılandırması oluşturmak için gereken temel adımlar özetlenmektedir. Bu örnekte, iletiler hesap makinesi hizmetinin roundingCalc (v1) ve regularCalc (v2) iki farklı sürümüne yönlendirilir. Her iki uygulama da aynı işlemleri destekler; ancak eski hizmeti, roundingCalcdöndürmeden önce tüm hesaplamaları en yakın tamsayı değerine yuvarlar. İstemci uygulamasının yeni regularCalc hizmetin kullanılıp kullanılmayacağını belirtebilmesi gerekir.

Uyarı

Bir iletiyi belirli bir hizmet sürümüne yönlendirmek için Yönlendirme Hizmeti'nin ileti içeriğini temel alarak ileti hedefini belirleyebilmesi gerekir. Aşağıda gösterildiği gibi, istemci bir ileti üst bilgisine bilgi ekleyerek sürümü belirtir. İstemcilerin ek veri geçirmesini gerektirmeyen hizmet sürümü oluşturma yöntemleri vardır. Örneğin, bir ileti bir hizmetin en son veya en uyumlu sürümüne yönlendirilebilir veya yönlendirici standart SOAP zarfının bir bölümünü kullanabilir.

Her iki hizmet tarafından kullanıma sunulan işlemler şunlardır:

  • Ekle
  • Subtract
  • Çarpma
  • Böl

Her iki hizmet uygulaması da aynı işlemleri işlediğinden ve döndürdikleri veriler dışında temelde aynı olduğundan, istemci uygulamalarından gönderilen iletilerde bulunan temel veriler, isteğin nasıl yönlendirileceğini belirlemenize olanak tanıyacak kadar benzersiz değildir. Örneğin, her iki hizmet için de varsayılan eylemler aynı olduğundan Eylem filtreleri kullanılamaz.

Bu, hizmetin her sürümü için yönlendiricide belirli bir uç noktayı gösterme veya hizmet sürümünü belirtmek üzere iletiye özel üst bilgi öğesi ekleme gibi çeşitli yollarla çözülebilir. Bu yaklaşımların her biri, gelen iletileri hizmetin belirli bir sürümüne benzersiz olarak yönlendirmenizi sağlar, ancak benzersiz ileti içeriğini kullanmak farklı hizmet sürümleri için istekler arasında ayrım yapmak için tercih edilen yöntemdir.

Bu örnekte, istemci uygulaması istek iletisine 'CalcVer' özel üst bilgisini ekler. Bu üst bilgi, iletinin yönlendirilmesi gereken hizmetin sürümünü gösteren bir değer içerir. '1' değeri, iletinin roundingCalc hizmeti tarafından işlenmesi gerektiğini, '2' değeri ise normalCalc hizmetini gösterir. Bu, istemci uygulamasının hizmetin hangi sürümünün iletiyi işleyeceğini doğrudan denetlemesine olanak tanır. Özel üst bilgi iletinin içinde yer alan bir değer olduğundan, hizmetin her iki sürümünü de hedefleyen iletileri almak için bir uç nokta kullanabilirsiniz. bu özel üst bilgiyi iletiye eklemek için istemci uygulamasında aşağıdaki kod kullanılabilir:

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

Hizmet Sürümü Oluşturma Uygulama

  1. Hizmet tarafından kullanıma sunulan hizmet uç noktasını belirterek temel Yönlendirme Hizmeti yapılandırmasını oluşturun. Aşağıdaki örnek, iletileri almak için kullanılacak tek bir hizmet uç noktasını tanımlar. Ayrıca , (v1) ve regularCalc (v2) hizmetlerine ileti göndermek için roundingCalc kullanılacak istemci uç noktalarını tanımlar.

    <services>
        <service behaviorConfiguration="routingConfiguration"
                 name="System.ServiceModel.Routing.RoutingService">
          <host>
            <baseAddresses>
              <add baseAddress="http://localhost/routingservice/router" />
            </baseAddresses>
          </host>
          <!--Set up the inbound endpoint for the Routing Service-->
          <endpoint address="calculator"
                    binding="wsHttpBinding"
                    name="routerEndpoint"
                    contract="System.ServiceModel.Routing.IRequestReplyRouter" />
        </service>
    </services>
    <client>
    <!--set up the destination endpoints-->
          <endpoint name="regularCalcEndpoint"
                    address="net.tcp://localhost:9090/servicemodelsamples/service/"
                    binding="netTcpBinding"
                    contract="*" />
    
          <endpoint name="roundingCalcEndpoint"
                    address="http://localhost:8080/servicemodelsamples/service/"
                    binding="wsHttpBinding"
                    contract="*" />
        </client>
    
  2. İletileri hedef uç noktalara yönlendirmek için kullanılan filtreleri tanımlayın. Bu örnekte, iletinin hangi sürüme yönlendirilmesi gerektiğini belirlemek üzere "CalcVer" özel üst bilgisinin değerini algılamak için XPath filtresi kullanılır. XPath filtresi, "CalcVer" üst bilgisini içermeyen iletileri algılamak için de kullanılır. Aşağıdaki örnek, gerekli filtreleri ve ad alanı tablosunu tanımlar.

    <!-- 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 containing a value of 2-->
      <filter name="XPathFilterRegular" filterType="XPath"
              filterData="sm:header()/custom:CalcVer = '2'"/>
      <!--define an xpath message filter to look for the
          custom header containing a value of 1-->
      <filter name="XPathFilterRounding" filterType="XPath"
              filterData="sm:header()/custom:CalcVer = '1'"/>
       <!--define an xpath message filter to look for
           messages that do not contain the custom header-->
       <filter name="XPathFilterNoHeader" filterType="XPath"
               filterData="count(sm:header()/custom:CalcVer)=0"/>
    </filters>
    

    Not

    s12 ad alanı ön eki, ad alanı tablosunda varsayılan olarak tanımlanır ve ad alanını http://www.w3.org/2003/05/soap-envelopetemsil eder.

  3. Her filtreyi bir istemci uç noktasıyla ilişkilendiren filtre tablosunu tanımlayın. İletide değeri 1 olan "CalcVer" üst bilgisi varsa, normalCalc hizmetine gönderilir. Üst bilgi 2 değerini içeriyorsa, roundingCalc hizmetine gönderilir. Üst bilgi yoksa, ileti regularCalc'ye yönlendirilir.

    Aşağıdaki filtre tablosunu tanımlar ve daha önce tanımlanan filtreleri ekler.

    <filterTables>
      <filterTable name="filterTable1">
          <!--add the filters to the message filter table-->
          <!--look for the custom header = 1, and if we find it,
              send the message to the rounding calc endpoint-->
          <add filterName="XPathFilterRounding" endpointName="roundingCalcEndpoint"/>
          <!--look for the custom header = 2, and if we find it,
              send the message to the rounding calc endpoint-->
          <add filterName="XPathFilterRegular" endpointName="regularCalcEndpoint"/>
          <!--look for the absence of the custom header, and if
              it is not present, assume the v1 endpoint-->
          <add filterName="XPathFilterNoHeader" endpointName="roundingCalcEndpoint"/>
      </filterTable>
    </filterTables>
    
  4. Gelen iletileri filtre tablosundaki filtrelere göre değerlendirmek için, yönlendirme davranışını kullanarak filtre tablosunu hizmet uç noktalarıyla ilişkilendirmeniz gerekir. Aşağıdaki örnekte hizmet uç noktalarıyla ilişkilendirme filterTable1 gösterilmektedir:

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

Örnek 1

Aşağıda yapılandırma dosyasının tam listesi yer alır.

<?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 endpoint for the Routing Service-->
        <endpoint address="calculator"
                  binding="wsHttpBinding"
                  name="routerEndpoint"
                  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="http://localhost:8080/servicemodelsamples/service/"
                binding="wsHttpBinding"
                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 containing a value of 2-->
        <filter name="XPathFilterRegular" filterType="XPath"
                filterData="sm:header()/custom:CalcVer = '2'"/>
        <!--define an xpath message filter to look for the
            custom header containing a value of 1-->
        <filter name="XPathFilterRounding" filterType="XPath"
                filterData="sm:header()/custom:CalcVer = '1'"/>
        <!--define an xpath message filter to look for
            messages that do not contain the custom header-->
        <filter name="XPathFilterNoHeader" filterType="XPath"
                filterData="count(sm:header()/custom:CalcVer)=0"/>
      </filters>
      <filterTables>
        <filterTable name="filterTable1">
            <!--add the filters to the message filter table-->
            <!--look for the custom header = 1, and if we find it,
                send the message to the rounding calc endpoint-->
            <add filterName="XPathFilterRounding" endpointName="roundingCalcEndpoint"/>
            <!--look for the custom header = 2, and if we find it,
                send the message to the rounding calc endpoint-->
            <add filterName="XPathFilterRegular" endpointName="regularCalcEndpoint"/>
            <!--look for the absence of the custom header, and if
                it is not present, assume the v1 endpoint-->
            <add filterName="XPathFilterNoHeader" endpointName="roundingCalcEndpoint"/>
        </filterTable>
      </filterTables>
    </routing>
  </system.serviceModel>
</configuration>

Örnek 2

Aşağıda, istemci uygulamasının tam listesi yer alır.

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace Microsoft.Samples.AdvancedFilters
{
    //The service contract is defined in generatedClient.cs, generated from the service by the svcutil tool.

    //Client implementation code.
    class Client
    {
        static void Main()
        {
            //Print out the welcome text
            Console.WriteLine("This sample routes the Calculator Sample through the new WCF RoutingService");
            Console.WriteLine("Wait for all the services to indicate that they've started, then press");
            Console.WriteLine("<ENTER> to start the client.");

            while (Console.ReadLine() != "quit")
            {
                //Offer the Address configuration for the client
                Console.WriteLine("");
                Console.WriteLine("Welcome to the Calculator Client!");

                EndpointAddress epa;
                //set the default address as the general router endpoint
                epa = new EndpointAddress("http://localhost/routingservice/router/calculator");

                //Set up the CalculatorClient with the EndpointAddress, the WSHttpBinding, and the ICalculator contract.
                //We use the WSHttpBinding so that the outgoing has a message envelope.
                CalculatorClient client = new CalculatorClient(new WSHttpBinding(), epa);
                //client.Endpoint.Contract = ContractDescription.GetContract(typeof(ICalculator));

                //Ask the customer if they want to add a custom header to the outgoing message.
                //The Router will look for this header, and if so ignore the endpoint the message was
                //received on, and instead direct the message to the RoundingCalcService.
                Console.WriteLine("");
                Console.WriteLine("Which calculator service should be used?");
                Console.WriteLine("Enter 1 for the rounding calculator, 2 for the regular calculator.");
                Console.WriteLine("[1] or [2]?");

                string header = Console.ReadLine();

                //get the current operationContextScope from the client's inner channel
                using (OperationContextScope ocs = new OperationContextScope((client.InnerChannel)))
                {
                    //get the outgoing message headers element (collection) from the context
                    MessageHeaders messageHeadersElement = OperationContext.Current.OutgoingMessageHeaders;

                    //if they wanted to create the header, go ahead and add it to the outgoing message
                    if (header != null && (header=="1" || header=="2"))
                    {
                        //create a new header "RoundingCalculator", no specific namespace, and set the value to
                        //the value of header.
                        //the Routing Service will look for this header in order to determine if the message
                        //should be routed to the RoundingCalculator
                        messageHeadersElement.Add(MessageHeader.CreateHeader("CalcVer", "http://my.custom.namespace/", header));
                    }
                    else //incorrect choice, no header added
                    {
                        Console.WriteLine("Incorrect value entered, not adding a header");
                    }

                        //call the client operations
                        CallClient(client);
                }

                //close the client to clean it up
                client.Close();
                Console.WriteLine();
                Console.WriteLine("Press <ENTER> to run the client again or type 'quit' to quit.");
            }
        }

        private static void CallClient(CalculatorClient client)
        {
            Console.WriteLine("");
            Console.WriteLine("Sending!");
            // Call the Add service operation.
            double value1 = 100.00D;
            double value2 = 15.99D;
            double result = client.Add(value1, value2);
            Console.WriteLine("Add({0},{1}) = {2}", value1, value2, result);

            // Call the Subtract service operation.
            value1 = 145.00D;
            value2 = 76.54D;
            result = client.Subtract(value1, value2);
            Console.WriteLine("Subtract({0},{1}) = {2}", value1, value2, result);

            // Call the Multiply service operation.
            value1 = 9.00D;
            value2 = 81.25D;
            result = client.Multiply(value1, value2);
            Console.WriteLine("Multiply({0},{1}) = {2}", value1, value2, result);

            // Call the Divide service operation.
            value1 = 22.00D;
            value2 = 7.00D;
            result = client.Divide(value1, value2);
            Console.WriteLine("Divide({0},{1}) = {2}", value1, value2, result);

        }
    }
}

Ayrıca bkz.