930 likes | 1.04k Views
Komponentowe i rozproszone. WCF. M etody komunikacji w .NET. WebServices + WSE 1,2,3 Remoting WCF:. WCF. Jest częścią .NET Framework od w. 3.x Wymaga zainstalowanego frameworka 2.0 +3.x lub 4.x Może pracować na: Windows Vista, 7 Windows XP SP2
E N D
Metodykomunikacji w .NET • WebServices+ WSE 1,2,3 • Remoting • WCF:
WCF • Jest częścią .NET Framework od w. 3.x • Wymaga zainstalowanego frameworka 2.0+3.x lub 4.x • Może pracować na: • Windows Vista, 7 • Windows XP SP2 • Windows Server 2003 SP1, Windows 2008 • WCF współpracuje ze starymi klientami i/lub serwerami
Proxy Proxy Proxy Granice komunikacji Proces A Proces B AppDomain 1 AppDomain 3 WWW Klient Klient Serwis AppDomain 2 W komunikacji zawsze uczestniczy Proxy - jednolity model aplikacji, łatwiejsza rekonfiguracja Klient
Punkt dostępowy ABC serwisu ... Adress Contract Binding
Adres • Każdy serwis musi mieć unikalny adres • Adres obejmuje lokcję serwisu oraz protokół transportowy lub schemat komunikacji • Lokacja: • Maszyna, adres • port komunikacyjny, potok, kolejka • opcjonalnie ściezka lub URI (napis, GUID) • Schemat komunikacji: • HTTP, TCP • Peer Network (net.p2p) • IPC • MSMQ http://localhost:8001/MyService Net.pipe://localhost/MyPipe Net.msmq://localhost/Myservice
Binding • Dodatkowe aspekty komunikacji • protokół • synchroniczna/asynchroniczna • jedno/dwu kierunkowa • trwała/ulotna • natychmiastowa/kolejkowana Binding określa sposób komunikacji z konkretnym punktem dostepowym serwisu
Binding • Interoperability • Security (Default) • Session (Default) • Transaction • Duplx • Encoding (Default) • Streaming (Default) • BasicHttpBinding Basic1.1 • (None), Transport, Message, Mixed • (None) • (None) • n/a • Text, (MTOM) • Yes(Buffered) • WSHttpBinding • WS • Transport, (Message), Mixed • (None), Transport, Reliable Session • (None), Yes • n/a • Text, (MTOM) • No • WSDualHttpBinding • WS • (Message), None • (Reliable Session) • (None), Yes • Yes • Text, (MTOM) • No • WSFederationHttpBinding WS-Federat. • (Message), Mixed, None • (None), Reliable Session • (None), Yes • No • Text, (MTOM) • No • NetTcpBinding • .NET (Transport), Mess-age, None, Mixed • (Transport), Reliable Session, • (None), Yes • Yes • Binary • Yes(Buffered) • NetNamedPipeBinding • .NET • (Transport), None • None, (Transport) • (None), Yes • Yes • Binary • Yes(Buffered) • NetMsmqBinding • .NET • Message, (Transport), Both • (None) • (None), Yes • No • No • NetPeerTcpBinding • Peer • (Transport) • (None) • (None) • Yes • No • MsmqIntegrationBinding • MSMQ • (Transport) • (None) • (None), Yes • n/a • No Bindingi predefiniowane
Binding WCF 2 WCF ? Nie: MSMQ Client ? Tak: MsMQIntegration Nie: Legacy/Asmx : Tak: Bacic Nie: WS Tak: Disconnedted CallsMSMQ? Tak: MsMQ Nie: CrossMachine: Tak: TCP Nie: NamedPipes
Kontrakt • Niezależny od platformy sposób opisu serwisu • Service kontracts • Data contracts • Fault contracts • Message contracts Zalecanie jest definiowanie własnej przestrzeni nazw dla nowych kontraktów – pozwala to uniknąć ew. konfliktów z innymi dostawcami. [ServiceContract(NameSpace = „MyNamespace”)] Domyślna przestrzeń nazw to http://tempuri.org
Host IIS • wymusza HTTP (IIS5 wymusza jednakowy port) • wymagany plik (analog. do webserwisu) .swc (nazwa = adres bazowy) • plik może być utworzony ręcznie lub przez VS <%@ ServiceHost Language = ”C#” Debug=”true” CodeBehind = ”~/App_Code/MyService.cs” Service =”MyService” %> • W Web.Config konieczne jest wpisanie serwisów <system.serviceModel> <system> <service name=”MyNamespace.MyService”> </service> </system> </system.serviceModel>
Hosting w aplikacji • W App.Config konieczne jest wpisanie serwisów <system.serviceModel> <services> <service name=”MyNamespace.MyService”> </service> </services> </system.serviceModel> • Host musi zostać uruchomiony przed wołaniem (nie dotyczy in-proc) • Rejestracja serwisu przez użycie klasy ServiceHost Uri baseAdress1 = new Uri(„net.tcp://localhost:801/”); ServiceHost host1 = new ServiceHost(typeOf(MyService), baseAdress1); host1.Open(); ... host1.Close();
ServiceHost :ICommunicationObject • Metody: • Open, Close, Abort • Metody asynchroniczne: • BeginOpen, EndOpen, BeginClose, EndClose • Zdarzenia: • Opening, Opened, Closing, Closed, Faulted • Własciwość: • CommunicationState state • enum CommunicationState{ Created, Opened, Closed, Faulted, , Opening, Closing }
Windows Activation Server • Dostępny w Windows Vista, 7, 8, Server 2007 • Jest częścią IIS7/8 ale moze być konfigurowany i instalowany oddzielnie • Wymaga pliku .svc • Udostępnia m.in. : • application pooling, recykling, • zarządzanie iddle-time, • zarządzanie tożsamościami • izolację aplikacji
Konfiguracja programowa vs administracyjna • Konfiguracja programowa: • dynamiczna konfiguracja, ustalana w rune-time : usługi sa identyfikowane i podłaczane dynamicznie • całkowicie statyczna – wartosci sa „hardcoded” : nie mozna nic popsuć ale równiez nic poprawić • Konfiguracja administracyjna: • Pozostałe przypadki :administrator lub wdrożeniowiec u klienta jest w stanie dostosować działanie usług w szerokim stopniu do aktualnych potrzeb
Konfiguracja administracyjna <system.serviceModel> <services> <service name=”MyNamespace.MyService”> <endpoint adress = ”http://localhost:8001/MyService/” binding = ”wsHttpBinding” contract = ”MyNamespace.IMyContract” /> <endpoint adress = ”net.tcp://localhost:8002/MyService/” binding = ”netTcpBinding” contract = ”MyNamespace.IMyContract” /> </service> </services> </system.serviceModel> Punkty muszą różnić sie portem lub nazwą serwisu
Konfiguracja programowa ServiceHost host = new ServiceHost(typeOf(MyService)); Binding wsBinding = new WSHTTPBinding() Binding tcpBinding = new NetTcpBinding() tcpBinding. TransactionFlow = true; Host.AddServiceEndpoint((typeof(IMyContract),wsBinding,. ”http://localhost:8001/MyService/”); Host.AddServiceEndpoint((typeof(IMyContract),tcpBinding, ”net.tcp://localhost:8002/MyService/” host.Open();
Metadane Publikowanie/pobieranie opisu serwisu: • tradycyjnie przez HTTP-GET • Administracyjnie: należy uaktywnic w konfiguracji • Programowo: trzeba dodać zachowanie do kolekcji zachowań hosta serwisu • przez dedykowany punkt dostępowy MEX Serwis
Metadane <system.serviceModel> <services> <service name=”MyNamespace.MyService” behaviorConfiguration = ”MEXGET”> <host> <baseAdresses> <add baseAdress = ”http://localhost:8001” /> </baseAdresses> <host> </service> </services> <behaviors> <serviceBehaviors> <behavior name ”MEXGET”> <serviceMetadata httpEnabled = ”true” /> </behavior> </serviceBehaviors> </behaviors>
Metadane ServiceHost host = new ServiceHost(typeOf(MyService)); ServiceMetadataBehavior metadataBehavior= host.Description.Behaviors.Find< ServiceMetadataBehavior> if (metadataBehavior ==null) { metadataBehavior = new ServiceMetadataBehavior(); metadataBehavior.HttpGetEnabled = true; host.Description.Behaviors.Add(metadataBehavior); } host.Open();
MEX <system.serviceModel> <services> <service name=”MyNamespace.MyService” behaviorConfiguration = ”MEX”> <host> <baseAdresses> <add baseAdress = ”http://localhost:8001” /> <add baseAdress = ”net.pipe://localhost” /> </baseAdresses> <host> <endpoint adress = ”MEX” binding=”mexTcpBinding” contract = ”IMexDataExchange” > <endpoint adress = ”MEX” binding=”mexNamedPipeBinding” contract = ”IMexDataExchange” > <endpoint adress = ”MEX” binding=”mexHttpBinding” contract = ”IMexDataExchange” > </service> </services> <behaviors> <serviceBehaviors> <behavior name ”MEX”> <serviceMetadata/> </behavior> </serviceBehaviors> </behaviors>
MEX - programowo BindingElement bindingElmt = new TcpTransportBindingElement(); CustomBinding binding = new CustomBinding(bindingElmt ); Uri adress = new uri(”net.tcp://localhost:8001/”); ServiceHist host = new ServiceHost(typeOf(MyService), adress); ServiceMetadataBehavior metadataBehavior= host.Description.Behaviors.Find< ServiceMetadataBehavior> if (metadataBehavior ==null) { metadataBehavior = new ServiceMetadataBehavior(); host.Description.Behaviors.Add(metadataBehavior); } host.Open();
Klient • Generacja proxy • VS • SvcUtil adres /out:Proxy.cs • Konfiguracja • W pliku App.Config • Domyślna może być wygenerowana przez :SvcUtil adres /out:Proxy.cs /config:App.Config • WCF udostępnia SvcConfigEditor.exe
Klient konfiguracja <system.serviceModel> <client> <endpoint name = ”MyEndPoint1” adress = ”http://localhost:8001/MyService/” binding = ”wsHttpBinding” contract = ”MyNamespace.IMyContract” /> <endpoint name ”MyendPoint2” adress =”net.tcp://localhost:8002/MyService/” binding = ”netTcpBinding” contract = ”MyNamespace.IMyContract” /> </client> </system.serviceModel>
Konfiguracja “inproc” <system.serviceModel> <services> <service name=” MyService”> <endpoint name = ”MyendPoint” adress = ”net.pipe://localhost/MyPipe/” binding = ”netNamedPipeBinding” contract = ” IMyContract” /> </service> </services> <client> <endpoint adress = ”net.pipe://localhost/MyPipe/” binding = ”netNamedPipeBinding” contract = ” IMyContract” /> </client> </system.serviceModel>
Aktywacja proxy MyContractClient proxy = new (”MyEndpoint”); proxy.MyMethod(); proxy.Close(); Zalecane jest zamykanie proxy – powoduje to rozłaczenie sesji i zamyka ew. połączenia np.: using (MyContractClient proxy = new MyContractClient(”MyEndpoint”) ) { proxy.MyMethod(); } lub IMyContract proxy = new MyContractClient(”MyEndpoint”); using (proxy as IDisposeable) { proxy.MyMethod(); }
Timeout <system.serviceModel> <client> <endpoint name = ”MyEndPoint1” ... binding = ”wsHttpBinding” bindingConfiguration = ”LongTimeout” /> </client> <bindings> <wsHttpBinding> <binding name = ”LongTimeout” sendTimeout = ”00:05:00” /> </wsHttpBinding> </bindings> </system.serviceModel>
Timeout - Konfiguracja programowa Binding wsBinding = new WSHTTPBinding(); wsBinding.SendTimeout = TimeSpan.FromMinutes(5); EndpointAdress endpt = new EndpointAdress(”http://localhost:8001/MyService/”); MyContractClient proxy = new (”MyEndpoint”, wsBinding, endpt); proxy.MyMethod(); proxy.Close();
Logowanie <system.diagnostics> <trace autoflush="true" /> <sources> <source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true"> <listeners> <add name="sdt" type="System.Diagnostics.XmlWriterTraceListener" initializeData= "SdrConfigExample.e2e" /> </listeners> </source> </sources> </system.diagnostics>
Logowanie <system.serviceModel> <diagnostics> <messageLogging logEntireMessage="true" logMalformedMessages="false" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="false" maxMessagesToLog="3000" maxSizeOfMessageToLog="2000"/> </diagnostics> </system.serviceModel>
Logowanie Możebyćwłączonepostronie • serwisu • kienta Przeglądanielogów: SvcTraceViewer.exe
Monitoring <system.serviceModel> <diagnostics performanceCounters="All" /> </system.serviceModel> Service Performance Counters Call, Instance,Queued Messages, Reliable Messaging, Security,Transacted Operations. Endpoint Performance Counters Call, Reliable Messaging, Security,Transacted Operations. Operation Performance Counters Call, Security,Transacted Operations
WCF: ServiceContract DataContact Zarządzanie instancjami Operacje Obsługa błędów
Service Kontrakt [serviceContract] interface Icalculator { [OperationContract] int Add(int arg1, int arg2); };
Kontrakt- przeciążanie • Przeciążanie jest legalne dla interfejsu interface Icalculator { int Add(int arg1, int arg2); double Add(double arg1, double arg2); }; • Przeciążanie jest nielegalne dla kontraktu [serviceContract] interface Icalculator { [OperationContract(Name=AddInt)] int Add(int arg1, int arg2); [OperationContract(Name=AddDouble)] double Add(double arg1, double arg2); };
Kontrakt z dziedzieczeniem [serviceContract] interface ICalc { [OperationContract] int Add(int arg1, int arg2); }; [serviceContract] interface IMACalc : ICalc { [OperationContract] int Multiply(int arg1, int arg2); };
Zaimportowane proxy [serviceContract] interface IMACalc { [OperationContract(Action = ”.../ICalc/Add”, ReplyAction = ”.../ICalc/AddResponse”, ] int Add(int arg1, int arg2); [OperationContract(Action = ”.../IMACalc/Multiply”, ReplyAction = ”.../IMACalc/MultiplyResponse”)] int Multiply(int arg1, int arg2); }; partial class MACalcClient : ClientBase< IMACalc>, IMACalc { int Add(int arg1, int arg2) {...} int Multiply(int arg1, int arg2) {...} }; • Można „ręcznie” wprowadzić poprawki w proxy
Data Kontrakt Formalny sposób opisu jak dane natywne dla .NET, na których operuje serwer oraz klient są zamieniane na/z postać neutralną
Wykonanie zdalnej operacji Serializacja parametrów we. Transport Deserializacja parametrów we. Wykonanie operacji Deserializacja parametrów wy. Transport Serializacja parametrów wy.
Serializacja [Serializable] public class MyClass { public int x; pivate int y; [NonSerialized] public int z; }; Nie są serializowane prywatne składowe
Serializacja .Net oferuje 2 formatery: • binarny • SOAP XML WCF oferuje: • DataContractSerializer (serializuje tylko stan ob. bez inf. o typie) • NetDataContractSerializer formater kompatybilny z .NET (tj serilizuje stan+dodatkowe inf.)
Data Contract [DataContract] public struct contact { [DataMember] public string FirstName; string m_LastName; [DataMember] public string SecondName { get {...} set {...} } [DataMember] private string Adress; }; Elementem kontraktu mogą byc równiez składowe prywatne Typy moga być złożone
Importowane Data Contract [DataContract] public struct contact { string FirstNameField; [DataMember] public string FirstName { get {...} set {...} } ... }; Dane zawsze są importowane w postaci składowa+property Można to ręcznie zmienić atrybut Serializable (po stronie serwera) jest również aceptowany i tlumaczony na DatContract
Zdarzenia [DataContract] public struct contact { [DataMember] public string FirstName; [DataMember] string LastName; [OnSerializing] void OnSerializing(Streamingcontext context) {...} }; Dostępne są zdarzenia OnSerializing, OnSerialized, OnDeserializing, OnDeserialized OnDeserializing – może być użyte jako „konstruktor” przy deserial.
Stare i nowe Możliwe jest mieszanie Serialize i DataContract z powodu kompatybiloności ale zwykle to [DataContract] będzie dziedziczyć zawierać elementy [Serializable]
KnownType C# zezwala na zastąpienie opektu typem pochodnym WCF domyślnie nie pozwala na to. [DataContract] public struct Contact {...} [DataContract] public struct Customer : Contact { [DataMember] public int LastOrder; }
KnownType [ServiceContract] interface IContactManager { [OperationContract] void AddContract(Contact contact) {...} [OperationContract] Contact[] GetContacts() {...} } błąd czasu wykonania dla: Contact contact = new Customer(); ContactManagerClient proxy = new ContactManagerClient(); proxy.AddContact(contact);
KnownType Wymagane jest: [DataContract] [KnownType(typeof(Customer))] public struct Contact {...} [DataContract] public struct Customer : Contact { [DataMember] public int LastOrder; }; Wadą jest to że analogiczne podstawienie może mieć miejsce w każdym serwisie korzystającym z typu Contact
KnownType Alternatywą może być : [ServiceContract] interface IcontactManager { [OperationContract] [ServiceKnownType(typeof(Customer))] void AddContract(Contact contact) {...} [OperationContract] Contact[] GetContacts() {...} } Jeśli jest więcej klas pochodnych każda musi być wskazana ex-plicite