Programowanie Systemów Rozproszonych
Laboratorium 2
WCF
Paweł Paduch
paduch@tu.kielce.pl
Rozdział 1
Wstęp
1.1
Materiały pomocniczne
Do zajęć przydatne mogą być:
• materiały udostępniane przez prowadzących wykłady
• książki związane z tematyką programowania np. „Język C# 2010 i
plat-forma .NET“Andrew Troelsena
• książki związane z tematyką programowania współbieżnego np.
„Progra-mowanie równoległe i asynchroniczne w C# 5.0”
• kursy i poradniki w sieci np. http://www.centrumxp.pl/
1.2
Definicje
• WCF - Windows Communication Foundation. System integrujący wszyst-kie microsoftowe dotychczasowe technologie służące komunikacji
• Serwis - udostępnia jeden lub więcej Endpointów
• Endpoint - udostępnia jeden lub więcej Service Operation. Określa adres gdzie może być znaleziony serwis,Binding oraz kontrakty
• Binding - określa jak klient ma się komunikować z serwisem
Rozdział 2
Przykładowy Web Serwis
Po zalogowaniu się z menu start odnajdujemy program Microsoft Visual
Stu-dio 2010, lub nowszy.
2.1
Service Contract
Z górnego menu wybieramy: File-> New Project. W okienku jak na rysunku
Rysunek 2.1: Okienko wybierania nowego projektu
2.1zaznaczamy Visual C#->Windows WCF Service Library. Na dole wpisujemy nazwę projektu WcfServiceLibrary i nazwę solucji Lab2, potwierdzamy OK.
Powinny powstać nam 3 pliki: • IService1.cs
• Service.cs • App.config
Zmieniamy nazwę IService1.cs na ICalculator.cs. W interfejsie definiujemy jakie operacje będzie udostępniać nasz serwis.
Listing 2.1: ICalculator.cs 1 usingSystem; 2 usingSystem.Collections.Generic; 3 usingSystem.Linq; 4 usingSystem.Runtime.Serialization; 5 usingSystem.ServiceModel; 6 usingSystem.Text; 7 8 namespaceWcfServiceLibrary 9 { 10 [ServiceContract(Namespace="http://achilles.tu.kielce.pl")] 11 public interfaceICalculator
12 {
13 [OperationContract]
14 double Add(double n1,double n2); 15 [OperationContract]
16 double Subtract(double n1,double n2); 17 [OperationContract]
18 double Multiply(double n1,double n2); 19 [OperationContract]
20 double Divide(double n1,double n2); 21 }
22 }
2.2
Implementacja Kontraktu
Zmieniamy nazwę pliku Service1.cs na Calculator.cs
Ustawiamy dziedziczenie CalculatorService po ICalculator. Można posłużyć się rozwijanym menu by wygenerować automatycznie odpowiednie metody, jak na rysunku 2.2
Rysunek 2.2: Implementacja interfejsu
Listing 2.2: Zaimplementowane metody w CalculatorService.cs
1 public classCalculatorService : ICalculator 2 {
3 public double Add(double n1,double n2) 4 {
5 doubleresult = n1 + n2;
6 Console.WriteLine("Dodawanie liczb: Add({0},{1})", n1, n2); 7 Console.WriteLine("Wynik: {0}", result);
8 returnresult; 9 }
10
11 public double Subtract(double n1,double n2) 12 {
13 doubleresult = n1 - n2;
14 Console.WriteLine("Odejmowanie liczb: Subtract({0},{1})", n1, n2); 15 Console.WriteLine("Wynik: {0}", result);
16 returnresult; 17 }
18
19 public double Multiply(double n1,double n2) 20 {
21 doubleresult = n1 * n2;
22 Console.WriteLine("Mnożenie liczba: Multiply({0},{1})", n1, n2); 23 Console.WriteLine("Wynik: {0}", result);
24 returnresult; 25 }
26
27 public double Divide(double n1,double n2) 28 {
29 doubleresult = n1 / n2;
30 Console.WriteLine("Dzielenie liczb: Divide({0},{1})", n1, n2); 31 Console.WriteLine("Wynik: {0}", result);
32 returnresult; 33 }
34 }
2.3
App.config
Należy, zmienić nazewnictwo w pliku App.config z Service1 na
CalculatorSe-rviceoraz IService1 na ICalculator.
Listing 2.3: App.config
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration>
3
4 <system.web>
5 <compilation debug="true" /> 6 </system.web>
7 <!-- When deploying the service library project, the content of the config file
←-must be added to the host's
8 app.config file. System.Configuration does not support config files for libraries.
←---> 9 <system.serviceModel> 10 <services> 11 <service name="WcfServiceLibrary.CalculatorService"> 12 <host> 13 <baseAddresses>
14 <add baseAddress =
"http://localhost:8733←-/Design_Time_Addresses/WcfServiceLibrary/CalculatorService/" />
15 </baseAddresses> 16 </host>
17 <!-- Service Endpoints -->
18 <!-- Unless fully qualified, address is relative to base address supplied
←-above -->
19 <endpoint address="" binding="basicHttpBinding"
contract="←-WcfServiceLibrary.ICalculator">
20
<!--21 Upon deployment, the following identity element should be removed or
22 identity under which the deployed service runs. If removed, WCF will
←-infer an appropriate identity
23 automatically. 24 --> 25 <identity> 26 <dns value="localhost"/> 27 </identity> 28 </endpoint> 29 <!-- Metadata Endpoints -->
30 <!-- The Metadata Exchange endpoint is used by the service to describe
itself←-to clients. -->
31 <!-- This endpoint does not use a secure binding and should be secured or
←-removed before deployment -->
32 <endpoint address="mex" binding="mexHttpBinding"
contract="IMetadataExchange"←-/> 33 </service> 34 </services> 35 <behaviors> 36 <serviceBehaviors> 37 <behavior>
38 <!-- To avoid disclosing metadata information, 39 set the value below to false before deployment --> 40 <serviceMetadata httpGetEnabled="True"/>
41 <!-- To receive exception details in faults for debugging purposes, 42 set the value below to true. Set to false before deployment 43 to avoid disclosing exception information -->
44 <serviceDebug includeExceptionDetailInFaults="False" /> 45 </behavior> 46 </serviceBehaviors> 47 </behaviors> 48 </system.serviceModel> 49 50 </configuration>
2.4
Pierwsze uruchomienie
Już teraz można uruchomić nasz serwis wciskając F5. Serwis będzie hosto-wany w środowisku uruchomieniowym, włączony zostanie też prosty klient do testowania rozwiązań (rys. 2.3).
2.5
Hostowanie serwisu
Stworzymy sobie prostą aplikację konsolową hostującą nasz serwis.
1. Dodaj do solucji nowy projekt typu Console Application i nazwij ją
Cal-culatorHost.
2. We właściwościach projektu zmień Target framework na .NET Framework
4.5 (rys.2.4). Projekt zostanie przeładowany.
3. Dodaj referencję do WcfServiceLibrary. W solution explorerze prawym kla-wiszem myszy na klikamy na References i wybieramy Add reference. Wy-bieramy z menu z lewej strony Solution -> Projects i zaznaczamy
WcfSe-rviceLibrary (rys.2.5). Dzięki temu aplikacja będzie znała typy używane
w projekcie serwisu.
4. Dodaj referencję do System.ServiceModel. Podobnie jak wyżej, tylko na-leży wybrać nie Solution a Assemblies->Framework i tam zaznaczyć
Sys-tem.ServiceModel.
Rysunek 2.4: Właściwości projektu Uzupełnij kod w pliku Program.cs jak na listingu2.4
Listing 2.4: Główny program hostujący serwis
1 usingSystem; 2 usingSystem.Collections.Generic; 3 usingSystem.Linq; 4 usingSystem.Text; 5 usingSystem.ServiceModel; 6 usingWcfServiceLibrary;
Rysunek 2.5: Dodanie referencji do serwisu 7 usingSystem.ServiceModel.Description; 8 9 10 namespaceCalculatorHost 11 { 12 classProgram 13 {
14 static void Main(string[] args) 15 {
16 // Tworzymy adres gdzie pod którym będzie dostępna usługa
17 Uri baseAddress = new Uri("http://localhost:8000/CalculatorService/"); 18
19 // Tworzymy obiekt klasy CalculatorService
20 ServiceHost selfHost = newServiceHost(typeof(CalculatorService),
←-baseAddress);
21
22 try 23 {
24 // Dodajemy Endopoint usługi
25 selfHost.AddServiceEndpoint(typeof(ICalculator), new
WSHttpBinding(),←-"CalculatorService");
26
27 // Umożliwiamy wymianę metadanych
28 ServiceMetadataBehavior smb =newServiceMetadataBehavior(); 29 smb.HttpGetEnabled =true;
30 selfHost.Description.Behaviors.Add(smb); 31
32 // Startujemy serwis 33 selfHost.Open();
34 Console.WriteLine("Serwis działa....");
35 Console.WriteLine("Naciśnij <ENTER> by zakończyć."); 36 Console.WriteLine(); 37 Console.ReadLine(); 38 39 // zamykamy serwis 40 selfHost.Close(); 41 }
42 catch (CommunicationException ce) 43 {
44 Console.WriteLine("Przechwyciłem wyjątek: {0}", ce.Message); 45 selfHost.Abort();
46 } 47 } 48 } 49 }
W linii 25 tworzymy Endpoint serwisu. Jest on złożony z adresu, bindingu oraz kontraktów.
Kontrakt to ICalculator. Binding to WSHttpBinding, który jest predefiniowa-nym bindingiem. Od wersji .Net 4.0 podawanie bindingu nie jest wymagane. Zostanie on automatycznie wygenerowany dla wszystkich par bazowy adres i kontrakt.
W linii 28 umożliwiamy wymianę metadanych serwisu. Klienci używają meta-danych do wygenerowania proxy służących do komunikowania się z serwisem. Należy:
• stworzyć obiekt klasy ServiceMetadataBehavior • ustawić jego parametr HttpGetEnabled na true
• dodać „zachowanie” (behavior) do kolekcji System.ServiceModel.ServiceHost.Behaviors. W linii 33 otwieramy host do nasłuchiwania przychodzących komunikatów.
Ustawiamy projekt CalculatorHost jako StartUp Project i uruchamiamy.
Mo-żemy uruchomić przeglądarkę i wejść na adres: http://localhost:8000/CalculatorService/. Powinniśmy zobaczyć linki do plików WSDL oraz przykład prostego klienta.
2.6
Klient
Klient korzysta z klas proxy wygenerowanych na podstawie metadanych. Metadane często są w postaci pliku WSDL (plik xmlowy opisujący web service). Klasy proxy można wygenerować za pomocą narzędzia Svcutil.exe dostępnego z konsoli Visual Studio Command Prompt lub z poziomu Visual Studio.
1. Dodaj nowy projekt typu aplikacja konsolowa o nazwie
CalculatorClient-Programdo solucji Lab2.
2. Ustaw we właściwościach projektu Target Framework na .Net 4.5 3. Dodaj referencje do System.ServiceModel
4. Dodaj dodaj referencje do servisu. W tym celu należy:
• Uruchomić program CalculatorHost tak by serwis działał i wystawił metadane na adresie http://localhost:8000/CalculatorService/. Nale-ży uruchomić w trybie bez debugowania (ctrl+F5).
• Prawym klawiszem myszy kliknąć w solution explorerze na References w projekcie CalculatorClientProgram i wybrać Add Service Reference. • podać adres serwisu i nacisnąć guzik Go.
• po odkryciu naszego serwisu podajemy nazwę przestrzeni nazw
Cal-culatorServiceReference(rys.2.7) i naciskamy OK.
• zostanie wygenerowany kod do klas proxy oraz plik konfiguracyjny
Rysunek 2.7: Dodaj referencje do serwisu
5. Jeżeli chcielibyśmy użyc narzędzia Svcutil.exe należałoby podać mniej wię-cej taką komendę:
svcutil.exe /language:cs /out:generatedProxy.cs /config:app.config http://localhost:8000/ServiceModelSamples/service
6. Uzupełniamy kod programu o odpowiednią przestrzeń nazw oraz tworzy-my obiekt klasy CalculatorClient wołatworzy-my prostą metodę client.Add jak listeningu (2.5)
Listing 2.5: Calculator Client
1 usingSystem; 2 usingSystem.Collections.Generic; 3 usingSystem.Linq; 4 usingSystem.Text; 5 usingCalculatorClientProgram.CalculatorServiceReference; 6 7 namespaceCalculatorClientProgram 8 { 9 classProgram 10 {
11 static void Main(string[] args) 12 {
13 //krok 1: Tworzymy obiekt klasy proxy
14 CalculatorClient client = newCalculatorClient(); 15
16 // Krok 2: Zawołaj metodę serwisu 17 // Dodawanie
18 double value1 = 100.00D; 19 double value2 = 15.99D;
20 double result = client.Add(value1, value2);
21 Console.WriteLine("{0} + {1} = {2}", value1, value2, result); 22
23 /// Tu dodaj kolejne wywołania metod 24
25
26 // Krok 3: zamknij połączenie i wyczyść 27 client.Close();
28 Console.ReadLine(); 29 }
30 } 31 }
Rozdział 3
Zadania do samodzielnego
wykonania
1. W programie klienta przetestować pozostałe 3 metody. (1pkt.)
2. Dodać do WcfServiceLibrary metodę liczącą potęgę Xy. Odświeżyć
refe-rencje CalculatorServiceReference. Zademonstrować działanie nowej me-tody w programie klienta. (1pkt.)
3. Dodać do WcfServiceLibrary metodę liczącą sumę wszystkich elementów listy List<double> (przy właściwościach CalculatorServiceReference nale-ży zmienić Collection type na System.Collections.Generic.List albo wyko-nać konwersję listy double do tablicy double. Zaprezentować nową metodę w programie klienckim. (1pkt.)
4. Stwórz nową usługę, w której będzie można wykonać następujące operacje: • Podaj ile liter ma łańcuch znakowy
• Połącz teksty
• Posortuj tablicę liczb typu int
Usługa powinna być hostowana w programie konsolowym. Demonstracja działania w osobnym programie klienckim. (2pkt.)