Laboratorium 3

Transkrypt

Laboratorium 3
Programowanie Systemów Rozproszonych
Laboratorium 3
WCF
Paweł Paduch [email protected]
12-04-2016
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 platforma .NET“ Andrew Troelsena
• książki związane z tematyką programowania współbieżnego np. „Programowanie równoległe i asynchroniczne w C# 5.0”
• kursy i poradniki w sieci np. http://www.centrumxp.pl/
• Tutoriale Microsoftu np. https://msdn.microsoft.com/en-us/library/ms731064(v=vs.110).aspx
- na tym bazuje poniższa instrukcja.
1
Rozdział 2
Komunikacja
dwukierunkowa - kontrakty
Po zalogowaniu się z menu start odnajdujemy program Microsoft Visual Studio 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.1 zaznaczamy Visual C#->Windows WCF Service Library. Na dole wpisujemy
nazwę projektu DuplexServiceLibrary i nazwę solucji Lab3, potwierdzamy OK.
Powinny powstać nam 3 pliki:
• IService1.cs
2
• Service.cs
• App.config
Zmieniamy nazwę IService1.cs na IDuplexCalc.cs. W interfejsie definiujemy
jakie operacje będzie udostępniać nasz serwis, (dodawanie, odejmowanie, mnożenie, dzielenie) ale też definiujemy jakie operacje może wywoływac u klienta.
Będą to odpowiednio Wyświetlenie wyniku i wyświetlenie równania.
Listing 2.1: IDuplexCalc.cs
1
2
3
4
5
6
using
using
using
using
using
using
System;
System.Collections.Generic;
System.Linq;
System.Runtime.Serialization;
System.ServiceModel;
System.Text;
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
namespace DuplexServiceLibrary
{
[ServiceContract(SessionMode = SessionMode.Required,
CallbackContract = typeof(IDuplexCalcCallback))]
public interface IDuplexCalc
{
[OperationContract(IsOneWay = true)]
void Wyczysc();
[OperationContract(IsOneWay = true)]
void DodajDo(double n);
[OperationContract(IsOneWay = true)]
void OdejmijOd(double n);
[OperationContract(IsOneWay = true)]
void PomnozPrzez(double n);
[OperationContract(IsOneWay = true)]
void PodzielPrzez(double n);
}
24
25
26
27
28
29
30
31
32
}
public interface IDuplexCalcCallback
{
[OperationContract(IsOneWay = true)]
void Wynik(double result);
[OperationContract(IsOneWay = true)]
void Rownanie(string eqn);
}
2.2
Implementacja Kontraktu
Zmieniamy nazwę pliku Service1.cs na DuplexCalc.cs
Ustawiamy dziedziczenie DuplexCalc po IDuplexCalc. Można posłużyć się rozwijanym menu by wygenerować automatycznie odpowiednie metody. Implementujemy poszczególne metody jednocześnie implementując właściwość Calback
zwracającą kanał zwrotny typu IDuplexCalcCallback
Listing 2.2: Zaimplementowane metody w DuplexCalc.cs
1
2
3
4
5
6
using
using
using
using
using
using
System;
System.Collections.Generic;
System.Linq;
System.Runtime.Serialization;
System.ServiceModel;
System.Text;
7
8
namespace DuplexServiceLibrary
3
9
{
10
11
12
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ←ConcurrencyMode = ConcurrencyMode.Single)]
public class DuplexCalc : IDuplexCalc
{
13
double wynik = 0.0D;
string rownanie;
14
15
16
public DuplexCalc()
{
rownanie = wynik.ToString();
}
17
18
19
20
21
public void Wyczysc()
{
Callback.Rownanie(rownanie + " = " + wynik.ToString());
rownanie = wynik.ToString();
}
22
23
24
25
26
27
public void DodajDo(double n)
{
wynik += n;
rownanie += " + " + n.ToString();
Callback.Wynik(wynik);
}
28
29
30
31
32
33
34
public void OdejmijOd(double n)
{
wynik -= n;
rownanie += " - " + n.ToString();
Callback.Wynik(wynik);
}
35
36
37
38
39
40
41
public void PomnozPrzez(double n)
{
wynik *= n;
rownanie += " * " + n.ToString();
Callback.Wynik(wynik);
}
42
43
44
45
46
47
48
public void PodzielPrzez(double n)
{
wynik /= n;
rownanie += " / " + n.ToString();
Callback.Wynik(wynik);
}
49
50
51
52
53
54
55
IDuplexCalcCallback Callback
{
get
{
return OperationContext.Current.GetCallbackChannel<←IDuplexCalcCallback>();
}
}
56
57
58
59
60
61
62
63
64
65
}
2.3
}
App.config
Należy, zmienić nazewnictwo w pliku App.config z Service1 na DuplexCalculator oraz IService1 na IDuplexCalc. Zmienić też typ bindingu z BasicHttpBinding na wsDualHttpBinding. Dodać sekcje bindings z definicją wsDualHttpBinding wszystko jak na listeningu App.config
4
Listing 2.3: App.config
1
2
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
3
<system.web>
<compilation debug="true" />
</system.web>
<!-- When deploying the service library project, the content of the config file ←must be added to the host's
app.config file. System.Configuration does not support config files for libraries. ←-->
<system.serviceModel>
<services>
<service name="DuplexServiceLibrary.DuplexCalc">
<endpoint address="" binding="wsDualHttpBinding" contract="←DuplexServiceLibrary.IDuplexCalc" bindingConfiguration="DuplexBinding">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"←/>
<host>
<baseAddresses>
<add baseAddress="http://localhost:8733←/Design_Time_Addresses/DuplexServiceLibrary/DuplexCalculator/" />
</baseAddresses>
</host>
</service>
</services>
<bindings>
<wsDualHttpBinding>
<binding name="DuplexBinding" clientBaseAddress="http://localhost:8000←/DuplexCalc/"/>
</wsDualHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the value below to false before deployment -->
<serviceMetadata httpGetEnabled="True"/>
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
</configuration>
2.4
Pierwsze uruchomienie
Już teraz można uruchomić nasz serwis wciskając F5. Serwis będzie hostowany w środowisku uruchomieniowym, włączony zostanie też prosty klient do
testowania rozwiązań (rys. 2.2).
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ą DuplexServiceHost.
5
Rysunek 2.2: WCF Test Client
2. We właściwościach projektu zmień Target framework na .NET Framework
4.5 (rys. 2.3). Projekt zostanie przeładowany.
3. Dodaj referencję do DuplexServiceLibrary. W solution explorerze prawym
klawiszem myszy na klikamy na References i wybieramy Add reference.
Wybieramy z menu z lewej strony Solution -> Projects i zaznaczamy DuplexServiceLibrary (rys. 2.4). 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 należy wybrać nie Solution a Assemblies->Framework i tam zaznaczyć System.ServiceModel.
Uzupełnij kod w pliku Program.cs jak na listingu ??
Listing 2.4: Główny program hostujący serwis
1
2
3
4
5
6
7
using
using
using
using
using
using
using
System;
System.Collections.Generic;
System.Linq;
System.ServiceModel;
System.ServiceModel.Description;
System.Text;
DuplexServiceLibrary;
8
9
10
11
12
13
14
15
16
namespace DuplexServiceHost
{
class Program
{
static void Main(string[] args)
{
// Tworzymy adres pod którym będzie dostępna usługa
Uri baseAddress = new Uri("http://localhost:8001/DuplexCalcService/");
17
18
19
// Tworzymy obiekt klasy DuplexCalc
ServiceHost selfHost = new ServiceHost(typeof(DuplexCalc), baseAddress);
20
21
22
23
try
{
// Dodajemy Endopoint usługi
24
25
selfHost.AddServiceEndpoint(typeof(IDuplexCalc), new ←WSDualHttpBinding() , "CalculatorService");
6
Rysunek 2.3: Właściwości projektu
Rysunek 2.4: Dodanie referencji do serwisu
7
26
// Umożliwiamy wymianę metadanych
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
// Umożliwiamy przesłanie dodatkowych danych na temat wyjątku
selfHost.Description.Behaviors.Find<ServiceDebugBehavior>().←IncludeExceptionDetailInFaults = true;
selfHost.Description.Behaviors.Add(smb);
27
28
29
30
31
32
33
34
// Startujemy serwis
selfHost.Open();
Console.WriteLine("Serwis działa....");
Console.WriteLine("Naciśnij <ENTER> by zakończyć.");
Console.WriteLine();
Console.ReadLine();
35
36
37
38
39
40
41
// zamykamy serwis
selfHost.Close();
42
43
44
45
46
47
48
49
50
51
52
}
}
}
}
catch (CommunicationException ce)
{
Console.WriteLine("Przechwyciłem wyjątek: {0}", ce.Message);
selfHost.Abort();
}
W linii 25 tworzymy Endpoint serwisu. Jest on złożony z adresu, bindingu
oraz kontraktów.
Kontrakt to IDuplexCalc. Binding to WSDualHttpBinding, który jest predefiniowanym bindingiem, umożliwia on komunikację dwustronną. 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ą metadanych 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 lini 31 umożliwiamy przesyłanie błędów z serwisu do klienta.
W linii 36 otwieramy host do nasłuchiwania przychodzących komunikatów.
Ustawiamy projekt DuplexServiceHost jako StartUp Project i uruchamiamy.
Możemy uruchomić przeglądarkę i wejść na adres: http://localhost:8001/DuplexCalcService/.
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.
8
Rysunek 2.5: Serwis w przeglądarce
9
1. Dodaj nowy projekt typu aplikacja konsolowa o nazwie DuplexCalcClient
do solucji Lab3.
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 serwisu. W tym celu należy:
• Uruchomić program CalculatorHost tak by serwis działał i wystawił
metadane na adresie http://localhost:8001/DuplexCalcService/. Należy uruchomić w trybie bez debugowania (ctrl+F5).
• Prawym klawiszem myszy kliknąć w solution explorerze na References
w projekcie DuplexCalcClient i wybrać Add Service Reference.
• podać adres serwisu i nacisnąć guzik Go.
• po odkryciu naszego serwisu podajemy nazwę przestrzeni nazw DuplexCalcServiceRef (rys. 2.6) i naciskamy OK.
Rysunek 2.6: Dodaj referencje do serwisu
• zostanie wygenerowany kod do klas proxy oraz plik konfiguracyjny
app.config.
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:8001/DuplexCalcService/
10
6. W kodzie musimy stworzyć klasę implementującą wywołania serwisu na
kliencie CallbackHandler. Są tam dwie metody Wynik i Rownanie. Serwis
za każdym razem gdy wołamy metodę liczacą, wywołuje u klienta metodę
zwracająca wynik.
7. Uzupełniamy kod programu o odpowiednią przestrzeń nazw oraz tworzymy obiekt klasy DuplexCalcClient wołamy metody operujące na kalkulatorze np DodajDo czy PomnozPrzez jak listeningu (2.5)
Listing 2.5: Calculator Client
1
2
3
4
5
6
using
using
using
using
using
using
System;
System.Collections.Generic;
System.Linq;
System.ServiceModel;
System.Text;
DuplexCalcProgram.DuplexCalcServiceRef;
7
8
9
namespace DuplexCalcProgram
{
10
public class CallbackHandler : IDuplexCalcCallback
{
public void Wynik(double result)
{
Console.WriteLine("Wynik({0})", result);
}
11
12
13
14
15
16
17
public void Rownanie(string eqn)
{
Console.WriteLine("Równanie({0})", eqn);
}
18
19
20
21
}
class Program
{
static void Main(string[] args)
{
22
23
24
25
26
27
28
());
InstanceContext instanceContext = new InstanceContext(new CallbackHandler←-
29
DuplexCalcClient client = new DuplexCalcClient(instanceContext);
client.Open();
client.DodajDo(5.0);
client.DodajDo(3.0);
client.PomnozPrzez(2.0);
client.PodzielPrzez(4.0);
client.OdejmijOd(1);
client.Wyczysc();
Console.ReadLine();
30
31
32
33
34
35
36
37
38
39
40
41
42
43
}
}
}
client.Close();
11
Rozdział 3
Zadania do samodzielnego
wykonania
Dodać do Callbacku wątek, który co sekundę woła metodę u klienta (licznikStan), która przekaże mu stan licznika. Licznik powinien startować od pierwszej
operacji wykonanej na serwisie i zatrzymywać się za pomocą innej zdalnej metody np licznikStop.
12