70-503: Configuring the Client Endpoint

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

Konfiguracja punkty wyjściowego (ang. endpoint) po stronie klienta przypomina tą, którą określa się w serwisie. Tak zwane ABC konfiguracji serwisu to address, binding, oraz contract. Konfiguracja może zostać przeprowadzona w sposób deklaratywny – z wykorzystaniem plików konfiguracyjnych, lub imperatywnie – przez kod.

Przykładowa deklaracja w postaci znaczników XML:

   1: <system.serviceModel>
   2:   <client>
   3:     <endpoint address="http://localhost:8080/UpdateService"
   4:     binding="wsHttpBinding"
   5:     contract="IUpdateService"
   6:     name="WSHttpBinding_IUpdateService">
   7:     </endpoint>
   8:   </client>
   9: </system.serviceModel>

W C# będzie to wyglądało następująco:

   1: EndpointAddress endpoint = new EndpointAddress("http://localhost:8080/UpdateService");
   2: UpdateServiceProxy proxy = new UpdateServiceProxy(new WSHttpBinding(), endpoint);

Adres określa położenie serwisu, binding określa sposób komunikacji, kontrakt – dostępne metody. Atrybut name nadaje nazwę punktowi wyjściowemu, przez co można odwołać się do niego w sposób programowy:

   1: UpdateServiceProxy proxy = new UpdateServiceProxy("WSHttpBinding_IUpdateService");

Jeżeli korzystamy ze standardowych bindingów zastosowane zostaną ich domyślne ustawienia. Aby określić dodatkowe opcje należy wykorzystać bindingConfiguration:

   1: <system.serviceModel>
   2:   <client>
   3:     <endpoint address="http://localhost:8080/UpdateService"
   4:     binding="WSHttpBinding"
   5:     bindingConfiguration="NameOfBinding"
   6:     contract="IUpdateService" />
   7:   </client>
   8:   <bindings>
   9:     <WSHttpBinding>
  10:       <binding name="NameOfBinding"
  11:       receiveTimeout="00:10:00"
  12:       sendTimeout="00:10:00"
  13:       openTimeout="00:10:00"
  14:       closeTimeout="00:10:00" />
  15:     </WSHttpBinding>
  16:   </bindings>
  17: </system.serviceModel>

 

 

Tworzymy binding programowo z wczytaniem powyższych opcji:

   1: WSHttpBinding binding = new WSHttpBinding("NameOfBinding");

 

 

W sekcji behaviorConfiguration możemy określić zachowanie bindingu:

   1: <system.serviceModel>
   2:   <client>
   3:     <endpoint address="http://localhost:8080/UpdateService"
   4:     binding="WSHttpBinding"
   5:     behaviorConfiguration="UpdateClient"
   6:     contract="IUpdateService" />
   7:   </client>
   8:   <behaviors>
   9:     <endpointBehaviors>
  10:       <behavior name="UpdateClient">
  11:         <clientCredentials>
  12:           <windows allowedImpersonationLevel="Identification" />
  13:         </clientCredentials>
  14:       </behavior>
  15:     </endpointBehaviors>
  16:   </behaviors>
  17: </system.serviceModel>

Element clientCredentials zapewnia wysłanie danych dotyczących uwierzytelniania i autoryzacji do serwisu.

Informacje dodatkowe

Wymienione wcześniej elementy to nie wszystkie, które można zastosować konfigurując endpoint. Przykładowym elementem, który można dodać jest header. Kiedy zostanie on zdefiniowany w pliku konfiguracyjnym, przy każdym żądaniu do serwisu. Przykładowa konfiguracja z wykorzystaniem nagłówków:

   1: <system.serviceModel>
   2:   <client>
   3:     <endpoint address="http://localhost:8080/UpdateOrder"
   4:     binding="wsHttpBinding"
   5:     contract="IUpdateService"
   6:     name="WSHttpBinding_UpdateOrder">
   7:       <headers>
   8:         <Priority xmlns="http://tempuri.org/">Expedite</Priority>
   9:       </headers>
  10:     </endpoint>
  11:     <endpoint address="http://localhost:8080/CancelOrder"
  12:     binding="wsHttpBinding"
  13:     contract="IUpdateService"
  14:     name="WSHttpBinding_CancelOrder">
  15:       <headers>
  16:         <Priority xmlns="http://tempuri.org/">Standard</Priority>
  17:       </headers>
  18:     </endpoint>
  19:   </client>
  20: </system.serviceModel>

W powyższym przykładzie zostały zdefiniowane dwa punkty wyjściowe. W zależności od tego, który zostanie wykorzystany podczas żądania, w nagłówku zostanie przekazana wartość Standard lub Expedite (przyspieszony). Serwis w zależności od tej wartości może inaczej obsłużyć żądanie.

W następnej lekcji – dynamiczna konfiguracja serwisu.

Tagi: , , , , ,

70-503: Service Endpoint Basics

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

Zakładamy, że stworzyliśmy już swój serwis. Mamy zdefiniowany kontrakt serwisu, oraz określone metody, które chcemy upublicznić. Teraz chcemy wystawić go (ang. expose) światu. Do tego służy właśnie punkt wejściowy (ang. endpoint), przez który klient może się z nim komunikować.

Endpoint pozwala nam określić gdzie nasz serwis będzie się znajdował (ang. address), w jaki sposób będziemy się z nim komunikować (ang. binding), oraz co serwis robi (ang. contract). Te trzy elementy to tzw. “ABCs of Endpoints”. ABC to trzy pierwsze litery nazw elementów.

Szybki start

W Visual Studio tworzymy przykładowy projekt typu WCF Service Library. Nazwijmy go przykładowo MyNamespace.Service.

image

Wśród wygenerowanych plików interesuje nas App.config. Warto go otworzyć.

Omówienie kodu

Wygenerowany plik to XML, który zawiera deklaratywny opis serwisu. Oto wytłumaczenie kluczowych jego fragmentów.

   1: <host>
   2:   <baseAddresses>
   3:     <add baseAddress = "http://localhost:8732/Design_Time_Addresses/MyNamespace.Service/Service1/" />
   4:   </baseAddresses>
   5: </host>

Zdefiniowany został tu adres bazowy (ang. base address), czyli część wspólna dla wszystkich adresów serwisu. Wprowadźmy tu prostszy zapis - http://localhost:8732/Service1.

Uwaga: Zamiana adresu wymaga uruchomienia Visual Studio z uprawnieniami administratora. W przeciwnym wypadku otrzymamy błąd.

image

Please try changing the HTTP port to 8732 or running as Administrator.
System.ServiceModel.AddressAccessDeniedException: HTTP could not register URL http://+:8732/Service1/. Your process does not have access rights to this namespace (see http://go.microsoft.com/fwlink/?LinkId=70353 for details). ---> System.Net.HttpListenerException: Access is denied
   at System.Net.HttpListener.AddAllPrefixes()
   at System.Net.HttpListener.Start()
   at System.ServiceModel.Channels.SharedHttpTransportManager.OnOpen()
   --- End of inner exception stack trace ---

W ramach znacznika endpoint zostały określone kluczowe parametry każdego punktu wejściowego.

1: <endpoint address ="" binding="wsHttpBinding" contract="MyNamespace.Service.IService1">

  • AddressURL, który identyfikuje położenie (adres) serwisu; w naszym wypadku pusty, gdyż zostanie wzięty z adresu bazowego,
  • Binding – wiązanie, określenie jaki sposób możemy otrzymać dostęp do serwisu; w naszym wypadku wykorzystany zostanie SOAP przez HTTP lub HTTPS.
    Inne możliwości to chociażby basicHttpBinding, wsDualHttpBinding, webHttpBinding, wsFederationHttpBinding, netTcpBinding, netNamedPipeBinding, netMsmqBinding, … 
    To, który binding wybierzemy zależy od kilku czynników specyficznych dla sieci oraz środowiska pracy. Przykładowo jeśli serwis jest uruchomiony na pojedynczej maszynie netNamedPipeBinding będzie najbardziej wydajny. Jeśli komunikacja ma następować pomiędzy dwoma komputerami wydajne okazać się wykorzystanie netTcpBinding lub netPeerTcpBinding. Jeśli współdziałanie pomiędzy różnymi środowiskami jest kluczową sprawą, a komunikujemy się pomiędzy komputerami bez zainstalowanego WCF’a – warto rozważyć zastosowanie basicHttpBinding lub wsHttpBinding.
  • Contract – kontrakt, który określa operacje upublicznione przez serwis; zwykle jest to nazwa interfejsu poprzedzona przestrzenią nazw (ang. namespace) projektu.

Znaczników endpoint może być dodanych wiele!

Metadane

Pod adresem http://localhost:8732/Service1/?wsdl (zakładając, że adres bazowy został zmieniony) dostępny opis serwisu w postaci pliku WSDL. Klient może uzyskać dostęp do tych danych za pomocą zwykłego zapytania HTTP-GET. Odpowiedzialne są za to dwa wiersze kodu:

   1: <!-- Wiersz 32. -->
   2: <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
   3: <!-- Wiersz 40. -->
   4: <serviceMetadata httpGetEnabled="True"/>

Zdefiniowany został tu “metadata exchange endpoint”punkt wymiany “serwujący” metadane. Ten punkt dodaje końcówkę mex do adresu HTTP wykorzystywanego przez serwis. Wykorzystuje on także IMetadataExchange jako kontrakt, oraz mexHttpBinding jako binding.

Gdybyśmy zechcieli wyłączyć udostępnianie danych opisujących serwis należy usunąć wymieniony znacznik endpoint oraz przypisać wartość False atrybutowi httpGetEnabled.

Opis za pomocą kodu

Wygenerowany XML to deklaratywny opis serwisu. To samo można zrobić z poziomu kodu. W tym celu utwórzmy nowy projekt typu Console Application, nazwijmy go MyNamespace.Host. Dodajmy w nim referencję do projektu z serwisem, oraz do komponentu System.ServiceModel. Plik App.config usuwamy. Nowy projekt ustawiamy jako domyślny.

Nowa zawartość pliku Program.cs:

   1: using System;
   2: using System.ServiceModel;
   3: using System.ServiceModel.Description;
   4:  
   5: namespace MyNamespace.Host
   6: {
   7:     class Program
   8:     {
   9:         static void Main(string[] args)
  10:         {
  11:             Uri baseAddress = new Uri("http://localhost:8732/Service1/");
  12:             ServiceHost host = new ServiceHost(typeof(MyNamespace.Service.Service1), baseAddress);
  13:  
  14:             BasicHttpBinding basicBinding = new BasicHttpBinding();
  15:             host.AddServiceEndpoint(typeof(MyNamespace.Service.IService1), basicBinding, "");
  16:  
  17:             // mex
  18:             ServiceMetadataBehavior mb;
  19:             mb = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
  20:             if (mb == null)
  21:             {
  22:                 mb = new ServiceMetadataBehavior();
  23:                 mb.HttpGetEnabled = true;
  24:                 host.Description.Behaviors.Add(mb);
  25:             }
  26:             host.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
  27:  
  28:             host.Open();
  29:             Console.WriteLine("Check WSDL at {0}?wsdl", baseAddress);
  30:             Console.Write("[CR] to break...");
  31:             Console.ReadLine();
  32:             host.Close();
  33:         }
  34:     }
  35: }

Uruchamiamy nasz program (F5) i cieszymy się :)

image

W następnej lekcji poznamy bardziej zaawansowane opcje związane z endpointami.

Tagi: , , , ,