Literatura Wprowadzenie Programowanie Systemów Rozproszonych - WCF REST Paweł Paduch Politechnika Świętokrzyska 11 kwietnia 2018 Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 1 z 44
Literatura Wprowadzenie Plan wykładu 1 Literatura Wprowadzenie 2 Per Call Per Session Single 3 2 Sharp Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 2 z 44
Literatura Wprowadzenie Literatura Strony dokumentacji MS https://msdn.microsoft.com/enus/library/dd456779(v=vs.110).aspx Andrew Troelsen - Język C# 2010 i platforma.net 4 Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 3 z 44
Literatura Wprowadzenie Wprowadzenie REST (ang. REpresentational State Transfer) Protokół przeznaczony do wymiany danych w systemach rozproszonych. REST został zdefiniowany po raz pierwszy w 2000 roku w rozprawie doktorskiej Architectural Styles and the Design of Network-based Software Architectures przez Roya Fieldinga. Założeniem REST a jest istnienie zasobów (ang. Resources) czyli źródeł danych oraz akcji. Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 4 z 44
Literatura Wprowadzenie Główne cechy a Proste operacje Minimalna ilość danych opakowujących Stosunkowo odporny na zmiany (np. Dodanie nowych pól) Dobry do zarządzania danymi (operacje CRUD). Słaba typizacja i brak standaryzacji utrudnia tworzenie serwisów obliczeniowych. Brak definicji utrudnia stosowanie narządzi wspomagających tworzenie klientów. Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 5 z 44
Literatura Wprowadzenie Operacje Operacja Dla kolekcji Dla elementu GET Pobiera kolekcję Pobiera element PUT Zamienia istniejącą kolekcję Zamienia element lub na nową tworzy nowy gdy brak POST Dodaje element do kolekcji Zwykle nie używane dla 1 elementu DELETE Usunięcie kolekcji Usunięcie elementu Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 6 z 44
Per Call Per Session Single Gdy wywołujemy metodę zdalną na serwerze tworzony jest obiekt klasy danej usługi. Serwer WCF Response Request Instancja WCF Rysunek: Instancja WCF Mamy trzy typy instancjis Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 7 z 44
Per Call Per Session Single Per Call InstanceContextMode.PerCall - na każde żądanie tworzony jest nowy obiekt. WCF 1 wywołanie metody 1 Odpowiedź 2 wywołanie metody 2 Odpowiedź Serwer 1 instancja WCF 2 instancja WCF Rysunek: Osobne instancje WCF na każde wywołanie metody. Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 8 z 44
Per Call Per Session Single Per Session InstanceContextMode.PerSession - dla każdej sesji klienckiej osobny obiekt. WCF 1 wywołanie metody 1 Odpowiedź 2 wywołanie metody Serwer Instancja WCF 2 Odpowiedź Rysunek: tworzone tylko na daną sesję. Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 9 z 44
Per Call Per Session Single Single InstanceContextMode.Single - Tworzona jest tylko 1 instancja dla wszystkich klientów. 1 WCF 2 WCF 1 wywołanie metody 1 Odpowiedź 2 wywołanie metody 2 Odpowiedź Serwer 1 instancja WCF Rysunek: Instancja singleton. Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 10 z 44
Nowy projekt Sharp Dodajemy do solucji nowy projekt WCF Service Application o nazwie Service Rysunek: Nowy projekt Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 11 z 44
Nowy Web Service Sharp Powstanie kilka plików i katalogów między innymi IService1.cs i Service1.svc.cs zmieńmy ich nazwę na PersonService. Rysunek: Nowy projekt Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 12 z 44
Sharp Person.cs Dodajemy nową klasę Person.cs reprezentującą osobę Listing 1: Person.cs 1 public class Person 2 { 3 public int Id { get; set; } 4 public string Name { get; set; } 5 public string Surname { get; set; } 6 } 7 Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 13 z 44
IPersonService.cs Sharp Listing 2: Zmiana w IPersonService.cs 1 [OperationContract] 2 [WebGet(UriTemplate = "Person/{id}")] 3 Person GetPerson(string id); 4 5 [OperationContract] 6 [WebGet] 7 List<Person> GetPersons(); 8 9 [OperationContract] 10 [WebInvoke(UriTemplate = "AddPerson/{name}/{surname}",Method = "GET")] 11 void AddPerson(string name, string surname); 12 13 [OperationContract] 14 [WebInvoke(UriTemplate = "UpdatePerson/{id}/{name}/{surname}")] 15 void UpdatePerson(string id, string name,string surname); 16 17 [OperationContract] 18 [WebInvoke(UriTemplate = "DeletePerson/{id}")] 19 void DeletePerson(string id); 20 Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 14 z 44
Sharp Rożnica pomiędzy WebInvoke a WebGet Gdy jest WebGet to jest to metoda GET Gdy jest WebInvoke to domyślnie jest metoda POST Gdy jest WebInvoke i ustawiona metoda np. Method = UPDATE to jest taka jak ustawiona Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 15 z 44
Sharp Rożnica pomiędzy WebInvoke a WebGet Wyjaśnienie różnic na przykładzie kodu z WebHttpBehavior.cs ze strony MS https://referencesource.microsoft.com/#system.servicemodel.web/system/servicemodel/description/webhttpbehavior.cs Listing 3: WebHttpBehavior.cs 1 internal static string GetWebMethod(OperationDescription od) 2 { 3 WebGetAttribute wga = od.behaviors.find<webgetattribute>(); 4 WebInvokeAttribute wia = od.behaviors.find<webinvokeattribute>(); 5 EnsureOk(wga, wia, od); 6 if (wga!= null) 7 { 8 return GET; 9 } 10 else if (wia!= null) 11 { 12 return wia.method?? POST; 13 } 14 else 15 { 16 return POST; 17 } 18 } 19 Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 16 z 44
PersonService.cs Sharp Listing 4: Implementacja interfejsu w PersonService.cs 1 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 2 public class PersonService : IPersonService 3 { 4 List<Person> persons = new List<Person>(); 5 int personcount = 0; 6 public void AddPerson(string name, string surname) 7 { 8 Person p = new Person() { Name = name, Surname = surname, Id=++personCount }; 9 persons.add(p); 10 } 11 public void DeletePerson(string id) 12 { 13 int Id = 0; 14 if (int.tryparse(id, out Id)) 15 { 16 persons.removeall(p => p.id == Id); 17 } 18 } 19 public Person GetPerson(string id) 20 { 21 int Id = 0; 22 if (int.tryparse(id, out Id)) 23 { 24 return persons.first<person>(p => p.id == Id); 25 } 26 } 27 public List<Person> GetPersons() 28 { 29 return persons.tolist(); 30 } 31 public void UpdatePerson(string id, string name, string surname) 32 { 33 Person p = GetPerson(id); 34 p.name = name; 35 p.surname = surname; 36 } 37 } 38 Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 17 z 44
Web.config Sharp Należy sprawdzić czy dodał nam się Service.PersonService. Poniżej fragment kodu. Listing 5: Web.config 1 <system.servicemodel> 2 <behaviors> 3 <endpointbehaviors> 4 <behavior name="restfulbehavior"> 5 <webhttp/> 6 </behavior> 7 </endpointbehaviors> 8 <servicebehaviors> 9 <behavior name="publishmetadata"> 10 <servicemetadata httpgetenabled="true" httpsgetenabled="true"/> 11 <servicedebug includeexceptiondetailinfaults="true"/> 12 </behavior> 13 </servicebehaviors> 14 </behaviors> 15 <services> 16 <service name="service.personservice" behaviorconfiguration="publishmetadata"> 17 <endpoint address="" 18 behaviorconfiguration="restfulbehavior" 19 binding="webhttpbinding" 20 bindingconfiguration="" 21 contract="service.ipersonservice"/> 22 </service> 23 </services> 24 <servicehostingenvironment aspnetcompatibilityenabled="true" multiplesitebindingsenabled="true"/> 25 </system.servicemodel> 26 Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 18 z 44
Uruchomienie Sharp Jeżeli projekt jest ustawiony jako domyślny do uruchomienia można wcisnąć F5. Rysunek: Uruchomienie i wywołanie serwisu Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 19 z 44
Uruchomienie Sharp pobrania danych. Rysunek: Pobranie danych Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 20 z 44
Sharp Dodajemy nowy projekt konsolowy o nazwie Client Rysunek: Nowy projekt Client Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 21 z 44
Sharp W Program.cs dodajemy obiekt klasy HttpClient oraz dwie metody asynchroniczne Listing 6: Program.cs 1 static HttpClient client = new HttpClient(); 2 static async Task<String> GetPersonsAsync(string path) 3 { 4 string persons = null; 5 HttpResponseMessage response = await client.getasync(path); 6 if (response.issuccessstatuscode) 7 { 8 persons = await response.content.readasstringasync(); 9 } 10 return persons; 11 } 12 static async Task<Uri> AddPersonAsync(string path, string imie, string nazwisko) 13 { 14 HttpResponseMessage response = await client.postasync(path + "/" + imie + "/" + nazwisko, null); 15 //HttpResponseMessage response = await client.getasync(path + "/" + imie + "/" + nazwisko); 16 response.ensuresuccessstatuscode(); 17 return response.headers.location; 18 } 19 Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 22 z 44
Sharp W funkcji main wołamy asynchroniczną metodę RunAsync Listing 7: Program.cs 1 static void Main(string[] args) 2 { 3 RunAsync().Wait(); 4 } 5 static async Task RunAsync() 6 { 7 client.baseaddress = new Uri("http://localhost:29585/"); 8 client.defaultrequestheaders.accept.clear(); 9 try 10 { 11 await AddPersonAsync("PersonService.svc/AddPerson", "Janko", "Muzykant"); 12 string persons = await GetPersonsAsync("PersonService.svc/GetPersons"); 13 Console.WriteLine(persons); 14 } 15 catch (Exception e) 16 { 17 Console.WriteLine(e.Message); 18 } 19 Console.ReadLine(); 20 } 21 Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 23 z 44
Sharp wywołaniaclient Rysunek: wywołania Client Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 24 z 44
Nowy projekt Sharp Dodajemy nowy projekt Service2 typu WCF Service Application Rysunek: Nowy projekt Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 25 z 44
Data Contract Sharp Usuwamy pliki IService1.cs i Service1.svc Dodajemy pliki IService.cs i Service.cs Dodajemy klasę Person 1 [DataContract] 2 public class Person 3 { 4 [DataMember] 5 public int Id { get; set; } 6 [DataMember] 7 public string Name { get; set; } 8 [DataMember] 9 public string Surname { get; set; } 10 } 11 Listing 8: Person.cs Dodajemy using System.Runtime.Serialization Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 26 z 44
Service Contract Sharp W interfejsie IService definiujemy webmetody oraz dodajemy przestrzenie nazw: using System.ServiceModel; i using System.ServiceModel.Web; Listing 9: IService.cs 1 [ServiceContract] 2 interface IService 3 { 4 [OperationContract] 5 [WebGet(UriTemplate = "{id}")] 6 Person GetPerson(string id); 7 8 [OperationContract] 9 [WebGet(UriTemplate = "")] 10 List<Person> GetPersons(); 11 12 [OperationContract] 13 [WebInvoke(UriTemplate = "", Method = "POST")] 14 Person AddPerson(Person person); 15 16 [OperationContract] 17 [WebInvoke(UriTemplate = "{id}", Method = "PUT")] 18 Person UpdatePerson(string id, Person person); 19 20 [OperationContract] 21 [WebInvoke(UriTemplate = "{id}", Method = "DELETE")] 22 void DeletePerson(string id); 23 } Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 27 z 44
Implementacja interfejsu Sharp Tworzymy implementację Listing 10: Sevice.cs 1 [AspNetCompatibilityRequirements (RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] 2 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 3 public class Service : IService 4 { 5 List<Person> persons = new List<Person>(); 6 int personcount = 0; 7 public Person GetPerson(string id) 8 { 9 int Id = 0; 10 if (int.tryparse(id, out Id)) 11 { 12 return persons.first<person>(p => p.id == Id); 13 } 14 return null; 15 } 16 17 public List<Person> GetPersons() 18 { 19 return persons.tolist(); 20 } Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 28 z 44
Web.config Sharp Zawartość tagu system.servicemodel zamieniamy na: Listing 11: Web.config 1 <servicehostingenvironment aspnetcompatibilityenabled="true"></servicehostingenvironment> 2 <standardendpoints> 3 <webhttpendpoint> 4 <standardendpoint name="" 5 helpenabled="true" 6 automaticformatselectionenabled="true"> 7 </standardendpoint> 8 </webhttpendpoint> Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 29 z 44
Global.asax Sharp Dodajemy nowy element Global.asax Rysunek: Plik Global.asax Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 30 z 44
Sharp Global.asax Modyfikujemy Listing 12: zawartość metody Application Start 1 RouteTable.Routes.Add(new ServiceRoute 2 ("Service", new WebServiceHostFactory(), typeof( Service))); 3 Dodajemy referencję do System.ServiceModel.Activation Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 31 z 44
Uruchomienie Sharp Teraz można ustawić jako domyślny projekt i uruchomić. Rysunek: Uruchomienie Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 32 z 44
Advanced Client Sharp Do testowania serwisu wykorzystującego xml/json można użyć wtyczkę do przeglądarki chrome Rysunek: Uruchomienie Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 33 z 44
Rysunek: Paweł PaduchUruchomienie Programowanie Systemów Rozproszonych - WCF REST 34 z 44 Advanced Client Sharp wywyołania metody POST z danymi w formacie json
Advanced Client Sharp pobrania danych GET json Rysunek: Uruchomienie Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 35 z 44
Sharp Sharp Dodajemy nowy projekt konsolowy o nazwie Client2 Rysunek: Nowy projekt Client2 Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 36 z 44
Sharp Sharp Do stworzenia klienta użyjemy biblioteki Sharp (resharp.org) Z menu kontekstowego projektu wybieramy ManageNuGetPackage Rysunek: Instalacja Sharp Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 37 z 44
Sharp Sharp Przechodzimy do zakładki Browse i wpisujemy w okienku wyszukiwania restsharp Wybieramy ze znalezionych odpowiedni pakiet i klikamy z prawej strony ikonkę do pobrania i instalacji Rysunek: Instalacja Sharp Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 38 z 44
Provider Sharp Dodajemy nową klasę Listing 13: Provider.cs 1 public class Provider 2 { 3 readonly string _url; 4 5 public Provider(string url) 6 { 7 _url = url; 8 } 9 10 public T Execute<T>(Request request) where T : new() 11 { 12 var client = new Sharp.Client(); 13 client.baseurl = new System.Uri(_url); 14 var response = client.execute<t>(request); 15 16 if (response.errorexception!= null) 17 { 18 const string message = "Error retrieving response. scheck inner details for more info."; 19 var twilioexception = new ApplicationException(message, response.errorexception); 20 throw twilioexception; 21 } 22 return response.data; 23 } 24 } Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 39 z 44
Person.cs Sharp Kopiujemy plik Person.cs z projektu Service Listing 14: Person.cs 1 public class Person 2 { 3 public int Id { get; set; } 4 public string Name { get; set; } 5 public string Surname { get; set; } 6 } Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 40 z 44
Main Sharp W głównym programie przykład wywołania dwóch metod POST i jednej GET Listing 15: Program.cs 1 try 2 { 3 Provider r = new Provider("http://localhost:23285/"); 4 var request = new Request("Service", Method.POST); 5 Person person = new Person(); 6 person.name = "Jan"; 7 person.surname = "Kowalski"; 8 request.addjsonbody(person); 9 var a = r.execute<person>(request); 10 var request2 = new Request("Service", Method.POST); 11 Person person2 = new Person(); 12 person2.name = "Anna"; 13 person2.surname = "Nowak"; 14 request2.addjsonbody(person2); 15 var b = r.execute<person>(request2); 16 var request3 = new Request("Service", Method.GET); 17 var c = r.execute<list<person>>(request3); 18 foreach (Person p in c) 19 { 20 Console.WriteLine("{0} {1} {2}", p.id, p.name, p.surname); 21 } 22 Console.ReadLine(); 23 } 24 25 catch (Exception ex) 26 { 27 Console.WriteLine(ex.Message.ToString()); 28 } Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 41 z 44
Sharp wywołanie Sharp Uruchomienie programu konsolowego Client2 Rysunek: Uruchomienie Client2 Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 42 z 44
Pytania Sharp? Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 43 z 44
koniec Sharp Dziękuję Państwu za uwagę. Paweł Paduch Programowanie Systemów Rozproszonych - WCF REST 44 z 44