70-503: Dynamic Service Configuration

Ten artykuł pochodzi z serii przygotowań do egzaminu 70-503: Windows Communication Foundation.

Jak zapewne zauważyliście z wcześniejszych lekcji, siła WCFa pochodzi między nimi z możliwości zmiany parametrów “transmisji”  bez zmiany ani jednej linijki kodu, rekompilacji, … Od tego mamy przecież plik konfiguracyjny. Możemy sobie napisać jedną aplikację, którą będziemy używać w wielu instancjach jednocześnie i wcale nie będą sobie przeszkadzać. O tym było w poprzednich lekcjach.

Dziś pokażę jak stworzyć sobie serwis całkowicie po stronie kodu C#. Może nam się to przydać np. w sytuacji gdy chcemy użytkownikowi ograniczyć/uprościć możliwość konfiguracji serwisu.

Klasy których użyjemy nazywają się odpowiednio do opcji które były ustawiane w plikach konfiguracyjnych. Zaczniemy od utworzenia obiektu hostującego serwis:

   1: ServiceHost host = new ServiceHost(typeof(Calculator));
   2: host.AddServiceEndpoint(typeof(ICalculator),
   3:     new NetTcpBinding(), "net.tcp://localhost:8000/Calculator");

Od razu w drugiej linii mamy pokazane jak zdefiniować ServiceEndpoint. Jako parametry podajemy interfejs definiujący kontrakt, binding i adres czyli znane nam już ABC. :) O kontraktach było pisane wcześniej więc przejdźmy od razu do adresów.

Budowanie adresu

Adres może być bezwzględny (pełny) czyli zawierający pełną ścieżkę wraz z domeną, lub względny (relatywny) gdzie domena i port są określane podczas tworzenia hosta, a przy dodawaniu ServiceEndpoint’a podajemy tylko ścieżkę. Ogólnie adres przyjmuje postać:

protocol://servername[:portNumber]/pathToEndpoint

Przykłady adresów (jak widać dla msmq format adresu jest zupełnie inny):

  • http://localhost/SubDirectory/UpdateService
  • net.tcp://localhost:8080/UpdateService
  • net.pipe://localhost/Directory/UpdateService
  • msmq.formatname:DIRECT=OS:.\private$\updateQueue

Adresem może być string (jak we wcześniejszym przykładzie) lub obiekt Uri:

   1: ServiceHost host = new ServiceHost(typeof(Calculator));
   2: Uri address = new Uri("net.tcp://localhost:8000/Calculator");
   3: host.AddServiceEndpoint(typeof(ICalculator),
   4:     new NetTcpBinding(), address);

Poniżej mamy kod robiący dokładnie to samo ale z użyciem adresowania relatywnego:

   1: ServiceHost host = new ServiceHost(typeof(Calculator),
   2:     new Uri[] { new Uri("net.tcp://localhost:8000") });
   3: host.AddServiceEndpoint(typeof(ICalculator),
   4:     new NetTcpBinding(), "Calculator");

Przydaje się ten sposób zwłaszcza gdy mamy dużo ServiceEndpoint’ów (o tym w kolejnym akapicie) i bez sensu byłoby do każdego doklejanie aktualnego adresu serwera.

Wiele “Punktów Końcowych”

Mamy możliwość utworzenia wielu punktów końcowych, z których każdy będzie odpowiadał innemu kontraktowi (oczywiście nasza klasa Calculator obsługująca serwis musi implementować oba interfejsy):

   1: ServiceHost host = new ServiceHost(typeof(Calculator));
   2: NetTcpBinding binding = new NetTcpBinding();
   3: host.AddServiceEndpoint(typeof(ICalculator),
   4:     binding, "net.tcp://localhost:8000/Calculator");
   5: host.AddServiceEndpoint(typeof(IMaszynkaLicząca),
   6:     binding, "net.tcp://localhost:8000/Calculator");

Należy tutaj zauważyć ze ta sama instancja obiektu NetTcpBinding została podana w obu wywołaniach AddServiceEndpoint. Jeśli podalibyśmy oddzielne instancje, za drugim razem dostalibyśmy wyjątek informujący o tym, że już jakaś instancja bindingu została przypisana do podanego adresu.

Możemy też utworzyć kilka punktów końcowych do tego samego kontraktu (różniące się bindingiem):

   1: ServiceHost host = new ServiceHost(typeof(Calculator));
   2: host.AddServiceEndpoint(typeof(ICalculator),
   3:     new NetTcpBinding(), "net.tcp://localhost:8000/Calculator");
   4: host.AddServiceEndpoint(typeof(ICalculator),
   5:     new WSHttpBinding(), http://localhost/Calculator);

Czytający Training Kit’a zauważą zapewne błąd w podanym tam przykładzie dla C#. W obu przypadkach powinien być użyty kontrakt IUpdateService. Dla VB jej poprawnie.

Metoda AddServiceEndpoint umożliwia podanie także URI listenera jako czwarty parametr wywołania. Dzięki temu część adresu będzie wspólna dla obu bindowań:

   1: ServiceHost host = new ServiceHost(typeof(Calculator));
   2: Uri commonUri = new Uri("net.tcp://localhost:8888/common");
   3: NetTcpBinding binding = new NetTcpBinding();
   4: host.AddServiceEndpoint(typeof(ICalculator),
   5:     binding, "/Calculator1", commonUri);
   6: host.AddServiceEndpoint(typeof(ICalculator),
   7:     binding, "/Calculator2", commonUri);

Po stronie klienta podłączenie do tego serwisu powinno wyglądać mniej więcej tak:

   1: EndpointAddress endpoint = new
   2:     EndpointAddress("net.tcp://localhost:8000/Calculator2");
   3: NetTcpBinding binding = new NetTcpBinding();
   4: Uri commonUri = new Uri("net.tcp://localhost:8888/common");
   5: CalculatorProxy proxy = new CalculatorProxy(binding, endpoint);
   6: proxy.Endpoint.Behaviors.Add(newViaUriBehavior(commonUri));

Binding

Właściwości bindowań zostały podzielone na tzw. Binding Elements, które są wspólne dla wielu rodzajów bindowań. Jeśli zrozumiemy działanie każdego “elementu” to będziemy wiedzieli jak działa binding, który zawiera dany element.

basicHttpBinding

basicHttpBinding ma 4 tryby zabezpieczeń (właściwość Security.Mode) . W zależności od trybu będą użyte inne elementy:

  • brak zabezpieczeń:
    TextMessageEncodingBindingElement, HttpTransportBindingElement
  • tryb Transport:
    TextMessageEncodingBindingElement, HttpsTransportBindingElement
  • tryb Message:
    TextMessageEncodingBindingElement, HttpTransportBindingElement, AsymmetricSecurityBindingElement
  • tryb TransportWithMessageCredentials:
    TextMessageEncodingBindingElement, HttpsTransportBindingElement, TransportSecurityBindingElement

Dodatkowo jeśli ustawimy MessageEncoding na Message Transmission Optimization Mechanism (MTOM) to zamiast TextMessageEncodingBindingElement zostanie użyty MtomMessageEncodingBindingElement.

Nazwy same w sobie powinny świadczyć o tym czym zajmuje się dany element i w jaki sposób to robi.

netTcpBinding

Jak sama nazwa wskazuje (czemu te nazwy są wszędzie takie intuicyjne? :) ) ten binding używa TCP jako podstawę. Używane są następujące elementy BinaryMessageEncodingBindingElement (konwertowanie wiadomości do postaci binarnej), TransactionFlowBindingElement (obsługa transakcji między klientem i serwisem), oraz TcpTransportBindingElement (obsługa transmisji).

netNamedPipeBinding

Składa się z trzech elementów: TransactionFlowBindingElement, BinaryMessageEncodingBindingElement, NamedPipeTransportBindingElement.

netMsmqBinding

Ten binding nie obsługuje transakcji, składa się tylko z dwóch elementów: BinaryMessageEncodingBindingElement, MsmqTransportBindingElement.

netPeerTcpBinding

Składa się z trzech elementów: BinaryMessageEncodingBindingElement, PnrpPeerResolverBindingElement (obsługuje Peer Name Resolution Protocol (PNRP) – protokół potrzebny do nawiązania komunikacji Peer-to-Peer), PeerTransportBindingElement.

wsDualHttpBinding

Oprócz przedstawionych wcześniej TransactionFlowBindingElement, TextMessageEncodingBindingElement i HttpTransportBindingElement korzysta też z elementów CompositeDuplexBindingElement (obsługa wywołania zwrotnego ang. callback) oraz ReliableSessionBindingElement (obsługa sesji czyli zachowanie kolejności komunikatów itp.).

Pozostały jeszcze:

basicHttpContextBinding

TextMessageEncodingBindingElement, HttpTransportBindingElement

msmqIntegrationBinding

BinaryMessageEncodingBindingElement,MsmqTransportBindingElement

netTcpContextBinding

BinaryMessageEncodingBindingElement,TransactionFlowBindingElement, TcpTransportBindingElement

webHttpBinding

TextMessageEncodingBindingElement,HttpTransportBindingElement 

wsFederationHttpBinding

TransactionFlowBindingElement, TextMessageEncodingBindingElement, HttpTransportBindingElement

wsHttpContextBinding

TransactionFlowBindingElement, TextMessageEncodingBindingElement, HttpTransportBindingElement

ws2007FederationhttpBinding

TransactionFlowBindingElement, TextMessageEncodingBindingElement, HttpTransportBindingElement

ws2007HttpBinding

TransactionFlowBindingElement, TextMessageEncodingBindingElement, HttpTransportBindingElement

W kolejnych kilku lekcjach zajmiemy się śledzeniem serwisów.

Tagi: , , ,

Add comment




  Country flag
biuquote
  • Comment
  • Preview
Loading


Eastgroup.pl na facebooku