Windows Communication Foundation

959 views
874 views

Published on

Przegląd najważniejszych elementów Windows Communication Foundation (WCF). Od wprowadzenia przez bardziej szczegółowe omówienie koncepcji bindingów, kontraktów, sposobów instancjonowania, obsługi błędów, bezpieczeństwa, itp.

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
959
On SlideShare
0
From Embeds
0
Number of Embeds
12
Actions
Shares
0
Downloads
13
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Windows Communication Foundation

  1. 1. Windows Communication Foundation Bartłomiej Zass ISV Developer Evangelist Microsoft
  2. 2. Od obiektów do usług Polimorfizm Hermetyzacja Dziedziczenie Komunikat Schemat + kontrakt + polisa Szeroka współpraca Położenie dowolne Ścisły związek Metadane w czasie działania Obiektowe UsługiKomponentowe 1980 20001990
  3. 3. Zadania serwera aplikacyjnego • „Pojemnik” na obiekty realizujące daną funkcjonalnośd – Jak pisad logikę obiektów? • Infrastruktura: transakcje, sesje, stan… • Mechanizmy komunikacji • Skalowalnośd: platforma + „opcje dla programisty” • Administrator: – Nadzór nad działaniem „platformowym” • Zużycie pamięci, procesora, wątki itp. – Monitorowanie działania „biznesowego” • O ile będzie rejestrowane w zrozumiały sposób… Serwer aplikacyjny to urządzenie które dostarcza aplikację do urządzeo klienckich (za Wikipedia). Komputer dedykowany do wykonania określonych programów/zadao. + architektura
  4. 4. MTS Komponenty Runtime aplikacji Deklaratywne transakcje i bezpieczeostwo Autoryzacja oparta o role COM+ Luźno powiązane zdarzenia Komponentyu kolejkowane „przepustnica” – nie więcej niż x komponentów Enterprise Services Model programowania w kodzie zarządzalnym Oparty o atrybuty, deklaratywny, konfiguracja w XML Windows Communication Foundation • Komunikaty oparte o XML • Dowolny transport • Zorientowane na usługi • Bezpieczeostwo: Federacja, CardSpace (dowody tożsamości) • Hosting - gdziekolwiek Ewolucja usług aplikacyjnych
  5. 5. -2002 2002-2006 2006- Problem – komunikacja…
  6. 6. 4 podstawowe doktryny SOA Wyraźne granice Usługi są autonomiczne Usługi dzielą kontrakt nie klasę Kompatybilność określana przez policy
  7. 7. Wprowadzenie do WCF
  8. 8. WCF: Adres, Binding, Kontrakt Klient Usługa KomunikatABC A B C A B C Adres Binding Kontrakt (Gdzie) (Jak) (Co) Endpoint Endpoint Endpoint Encoder Transport BasicHttp, WSHttp, WSDualHttp, WSFederation …Context… NetTcp, NetNamedPipe, NetPeerTcp NetMsmq, MsmqIntegration
  9. 9. WCF – standardowe bindingi Binding Interop Bezp. Sesja Trans. Duplex BasicHttpBinding BP 1.1 N, T N N n/a WSHttpBinding WS M, T, X N, T, RS N, Tak n/a WSDualHttpBinding WS M RS N, Tak Tak WSFederationBinding Federacja M N, RS N, Tak Nie NetTcpBinding .NET T, M T ,RS N, Tak Tak NetNamedPipeBinding .NET T T, N N, Tak Tak NetPeerTcpBinding Peer T N N Tak NetMsmqBinding .NET T, M, X N N, Tak Nie MsmqIntegrationBinding MSMQ T N N, Tak n/a N = Brak | T = Transport | M = Wiadomośd | B = Oba | RS = Pewna sesja
  10. 10. WCF – podstawy (wyjaśnienie) • Separacja kontraktu i implementacji • Wzorce komunikacyjne – Komunikacja jednokierunkowa (IsOneWay) – Zwracanie wartości – Sesja, – Kontrakt „zwrotny” (po stronie klienta) – Kontekst • Separacja szczegółów komunikacyjnych • Hosting: Jakkolwiek
  11. 11. WCF na jednym slajdzie Definicja „koocówki” Adres + Binding + Kontrakt Definicja kontraktu Implementacja usługi [ServiceContract] public interface IMyInterface { [OperationContract] void MyMethod(); [ServiceBehavior( InstanceContextMode=Single] public class MyService: IMyInterface { [OperationBehavior(Impersonation = ImpersonationOption.Required)] public void MyMethod() { … } <service name="MyService"> <endpoint address=“net.tcp://localhost:1234/MySvc" binding="netTcpBinding" contract="IMyInterface" />o
  12. 12. Kontrakt • Definiują funkcjonalnośd usługi. • Atrybuty kontraktu: – ServiceContract • OperationContract – DataContract – FaultContract – MessageContract • MessageBody • MessageHeader • Zachowania kontraktu – Sesja, transakcje, sposób inicjacji…
  13. 13. Kontrakt • Możliwośd implementacji wielu kontraktów • Publiczny konstruktor • [ServiceContract(Namespace = „”)+ – Domyślnie – tempuri.org – Intranet – np. nazwa aplikacji – Intenet – URL • Nazwa metody usługi – domyślnie z klasy – [OperationContract(Name = „…”)+
  14. 14. Host • IIS + WAS (Vista+, Windows Server 2008+) – Zarządzanie, skalowalnośd, itp. • IIS 5/6 – tylko HTTP – Web.config – eksponowane usługi • Self-hosting – InProc – szczególny przypadek (klient i serwer w tym samym procesie) – Między procesami – Między maszynami
  15. 15. ServiceHost public static void Main( ) { Uri baseAddress1 = new Uri("net. tcp: //localhost: 8001/"); ServiceHost host1 = new ServiceHost(typeof(MyService), baseAddress1) ; ServiceHost host = new ServiceHost(typeof(MyService)); host.Open( ); //Możliwe blokujące wywołania Application.Run(new MyForm( )); host.Close( ); } // WcfSvcHost
  16. 16. WAS • Nie ograniczony do HTTP – Dowolny transport, port, kolejka • Zalety vs self-hosting – Application pooling, recycling, zarządzanie idle- time, izolacja – Zalecane, kiedy dostępne Windows Server 2008 • Interakcja z procesem hosta <%@ ServiceHost Language = "C#" Debug = "true" CodeBehind = "~/App_Code/MyService. cs" Service = "MyService" Factory = "MyServiceFactory" %>
  17. 17. Service Factory class MyServiceFactory : ServiceHostFactory { protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses) { ServiceHost host = new ServiceHost(serviceType, baseAddresses); // Dodatkowe kroki – np. logowanie return host; } }
  18. 18. Bindingi • Protokół (HTTP, TCP, IPC, MSMQ) • Enkodowanie (plain text, MTOM) • Bezpieczeostwo (transport, komunikat) • …
  19. 19. Inne popularne bindingi • NetPeerTcpBinding • WSFederationHttpBinding • WS2007FederationHttpBinding • MsmqIntegrationBinding • WebHttpBinding • WS2007HttpBinding
  20. 20. Wybór bindingu
  21. 21. Endpoint • „Koocówka”, z którą możemy się komunikowad – Przynajmniej jeden dla każdej usługi • Dokładnie jeden kontrakt
  22. 22. Endpointy - konfiguracja <system.serviceModel = ""> <services> <service name = "MyNamespace.MyService"> <endpoint address = "http://localhost:8000/MyService" binding = "wsHttpBinding" contract = "MyNamespace.IMyContract„ bindingConfiguration = "TransactionalTCP /> </service> </services> <!–- <bindings> <netTcpBinding> <binding name = "TransactionalTCP" transactionFlow = "true" /> </netTcpBinding> </bindings> --> </system.serviceModel>
  23. 23. Metadane • Domyślnie – nie publikowane (nie przeszkadza w działaniu) • Dedykowany endpoint (MEX) – Eksponowany w dowolny sposób (HTTP, TCP, IPC) <endpoint address = "http: //localhost: 8000/MEX" binding = "mexHttpBinding" contract = "IMetadataExchange" /> • HTTP-GET (nie ma gwarancji interop) <behaviors> <serviceBehaviors> <behavior name = "MEXGET"> <serviceMetadata httpGetEnabled = "true"/> </behavior> </serviceBehaviors> </behaviors>
  24. 24. Po stronie klienta • Add service reference – automatycznie • SvcUtil SvcUtil http://localhost:8000/MEX /out:Proxy.cs • WcfTestClient. exe http: //localhost:9000/ • Ręcznie - kod public abstract class ClientBase<T> : ICommunicationObject, IDisposable { protected ClientBase(string endpointName); protected ClientBase(Binding binding, EndpointAddress remoteAddress); public void Open(); public void Close(); protected T Channel { get; } //... }
  25. 25. [ServiceContract(Namespace = "MyNamespace")] interface IMyContract { [OperationContract] void MyMethod(); } partial class MyContractClient : ClientBase<IMyContract>, IMyContract { public MyContractClient() { } public MyContractClient(string endpointName) : base(endpointName) { } public MyContractClient(Binding binding, EndpointAddress remoteAddress) : base(binding, remoteAddress) { } /* Dodatkowe konstruktory */ public void MyMethod() { Channel.MyMethod(); } }
  26. 26. Wywoływanie usługi MyContractClient proxy = new MyContractClient("MyEndpoint"); proxy.MyMethod( ); proxy.Close( ); // Można również using…
  27. 27. Bez generacji kodu - ChannelFactory Binding binding = new NetTcpBinding( ); EndpointAddress address = new EndpointAddress("net.tcp://localhost:8000"); IMyContract proxy = ChannelFactory<IMyContract>.CreateChannel(binding, address) ; using(proxy as IDisposable) { proxy.MyMethod( ); }
  28. 28. Transport session • Niektóre bindingi (np. basic – nie) • Mapowanie komunikatu na konkretny kontekst wywołujący operacje usługi • Reliability – Transport reliability – pakiety, itp. – Message reliability – kolejnośd (domyślnie) i informowanie kiedy nie dostarczono (ponawianie, itp.) <binding name = "ReliableTCP"> <reliableSession enabled = "true"/> </binding>
  29. 29. Kolejnośd komunikatów • Nie powinniśmy wymagad konkretnego bindingu, ale czasem istotna jest kolejnośd. [DeliveryRequirements(TargetContract = typeof(IMyContract), RequireOrderedDelivery = true) ] class MyService : IMyContract, IMyOtherContract { ... } [ServiceContract] [DeliveryRequirements(RequireOrderedDelivery = true) ] interface IMyContract { ... }
  30. 30. Kontrakt
  31. 31. Overloading // Błąd! [ServiceContract] interface ICalculator { [OperationContract] int Add(int arg1, int arg2); [OperationContract] double Add(double arg1, double arg2); } // Rozwiązanie: // [OperationContract(Name = „AddInt”)] // Proxy: AddInt -> również możliwa ręczna zmiana // nazw i OperationContract
  32. 32. Dziedziczenie • Możliwe, ale *ServiceContract] nie jest dziedziczony [ServiceContract] interface ISimpleCalculator { [OperationContract] int Add(int arg1, int arg2); } [ServiceContract] interface IScientificCalculator : ISimpleCalculator { [OperationContract] int Multiply(int arg1, int arg2); } // „Spłaszczane” po stronie klienta // Możliwe ręczne przywrócenie hierarchii po stronie klienta i usunięcie atrybutów // [OperationContract] [OperationContract(Action = "... /ISimpleCalculator/Add", ReplyAction = "... /ISimpleCalculator/AddResponse")] int Add(int arg1, int arg2) ; [OperationContract(Action = "... /IScientificCalculator/Multiply", ReplyAction = "... /IScientificCalculator/MultiplyResponse")] int Multiply(int arg1, int arg2) ;
  33. 33. Zgodnośd z kontraktem // Dynamiczna weryfikacja zgodności na podstawie WSDL bool contractSupported = false; Uri mexAddress = new Uri("...?WSDL") ; ServiceEndpointCollection endpoints = MetadataResolver. Resolve(typeof(ISimpleCalculator) , exAddress, MetadataExchangeClientMode. HttpGet) ; if(endpoints. Count > 0) { contractSupported = true; }
  34. 34. Kontrakty danych
  35. 35. Wymiana danych • Infoset – obsługiwane typy parametrów, … • Serializacja w .NET – [Serializable], [NonSerialized] – BinaryFormatter, SoapFormatter – wymaga .NET i konkretnego typu – WCF – DataContractSerializer – nie udostępnia informacji o typie; tylko kontrakt danych • Wyłącznie serializowalne typy – Klasa musi byd dostępna także po stronie klienta
  36. 36. Atrybuty kontraktu danych • Samo [Serializable] – zbyt ścisłe powiązanie • [DataContract] – Publikowane w MEX [DataContract] struct Contact { [DataMember] public string FirstName; [DataMember] public string LastName; } // *Dla uproszczenia bez właściwości // Właściwości mogą być private, koniecznie get i set
  37. 37. Zdarzenia serializacji • Np. inicjalizacja • [OnSerializing], [OnSerialized] [OnDeserializing], [OnDeserialized] [DataContract] class MyDataContract { [OnSerializing] void OnSerializing(StreamingContext context) {. . .} }
  38. 38. Inne • Współdzielenie kontraktu – Problem: ten sam typ w 2 serwisach (przestrzenie nazw) – „Reuse types in reference assemblies” • Dziedziczenie – [KnownType], [ServiceKnownType] // Customer : Contact Contact contact = new Customer( ); ContactManagerClient proxy = new ContactManagerClient( ); // Błąd w czasie działania proxy.AddContact(contact) ; proxy.Close( ); // ------------------------ [DataContract] [KnownType(typeof(Customer))] class Contact { ... } [DataContract] class Customer : Contact { ... }
  39. 39. Współdzielenie kontraktu • Zgodnośd z infoset - np. wersjonowanie • Dostosowanie klasy właściwością Name [DataContract(Name = "Contact")] struct Person { [DataMember(Name = "FirstName")] public string Name; [DataMember(Name = "LastName")] public string Surname; }
  40. 40. Współdzielenie a serializacja (1) • Od najbardziej ogólnej do najbardziej szczegółowej • Pola – alfabetycznie [DataContract] class Contact { [DataMember] public string FirstName; [DataMember] public string LastName; } [DataContract] class Customer : Contact { [DataMember] public int CustomerNumber; } // Infoset: Firstname, Lastname, CustomerNumber
  41. 41. Współdzielenie a serializacja (2) [DataContract(Name = "Customer")] public class Person { [DataMember(Name = "FirstName")] public string Name; [DataMember(Name = "LastName")] public string Surname; [DataMember] public int CustomerNumber; } // Kolejność: CustomerNumber, Firstname, Lastname [DataContract(Name = "Customer")] public class Person { [DataMember(Name = "FirstName", Order = 1)] public string Name; [DataMember(Name = "LastName", Order = 1)] public string Surname; [DataMember(Order = 2)] public int CustomerNumber; } // Kolejność zgodna z infoset: Firstname, Lastname, CustomerNumber
  42. 42. Wersjonowanie kontraktu • Dodawanie nowych pól – Nadmiarowośd jest dozwolona i kompatybilna • Brakujące pola – Wartości domyślne (null, itp.) – [OnDeserializing] – [DataMember(IsRequired = true)] – wyjątek – Problem z przekazywaniem dalej – utracona informacja
  43. 43. Wersjonowanie c.d. [DataContract] class Contact : IExtensibleDataObject { ExtensionDataObject IExtensibleDataObject.ExtensionData { get; set; } [DataMember] public string FirstName; [DataMember] public string LastName; } // Nie tracimy nadmiarowej informacji // Umożliwia to interakcję z serwisem spodziewającym się innego // kontraktu. Dlatego można wykluczyć taki scenariusz: [ServiceBehavior(IgnoreExtensionDataObject = true)] class ContactManager : IContactManager { ... } // Najlepsza praktyka: zawsze obsługa IExtensibleDataObject // unikać IgnoreExtensionDataObject
  44. 44. Sposoby instancjonowania
  45. 45. Kontekst
  46. 46. Zarządzanie kontekstem • Tryby instancjonowania kontekstów • Per Call • Per Session • Singleton
  47. 47. Per Call • Bezstanowośd, skalowalnośd – Konieczna inicjalizacja i zapis stanu [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)] class MyService : IMyContract { ... }
  48. 48. [ServiceContract] interface IMyContract { [OperationContract] void MyMethod( ); } [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall) ] class MyService : IMyContract, IDisposable { int m_Counter = 0; MyService( ) { Trace. WriteLine("MyService. MyService( )"); } public void MyMethod( ) { m_Counter++; Trace. WriteLine("Counter = " + m_Counter) ; } public void Dispose( ) { Trace. WriteLine("MyService. Dispose( )"); } } ///////////////////////// Client Code ///////////////////// MyContractClient proxy = new MyContractClient( ); proxy.MyMethod( ); proxy.MyMethod( ); proxy.Close( ); // Wyjście: MyService.MyService( ) Counter = 1 MyService.Dispose( ) MyService.MyService( ) Counter = 1 MyService.Dispose( )
  49. 49. Per Call i sesja komunikacyjna • Jeśli serwis ma tryb single-threaded i włączone transport session, żądania przetwarzane jeden po drugim – Bez sesji – możliwa losowa kolejnośd na wyjściu • Uwaga: Load Balancer i sesja – Sticky Sessions
  50. 50. Per Session • Domyślny tryb • Instancja utrzymywana w pamięci – Skalowalnośd [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)] class MyService : IMyContract { ... } • Wymagane transport session – Zalecane wymuszenie na poziomie kontraktu public enum SessionMode { Allowed, Required, NotAllowed } [ServiceContract(SessionMode = SessionMode.Allowed)] interface IMyContract {. . . }
  51. 51. Singleton • Tworzony wraz ze startem procesu hosta • Sesja nie wymagana – Po zakooczeniu, nadal instancja w pamięci [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)] class MyService : IMyContract { ... } • Możliwe przekazanie zainicjalizowanej instancji klasy do konstruktora hosta
  52. 52. Sesja a kontrakt • Atrybuty gwarantujące prawidłową kolejnośd wywołao [ServiceContract(SessionMode = SessionMode.Required)] interface IMyContract { [OperationContract] void StartSession(); [OperationContract(IsInitiating = false)] void CannotStart(); [OperationContract(IsTerminating = true)] void EndSession(); [OperationContract(IsInitiating = false, IsTerminating = true)] void CannotStartCanEndSession(); }
  53. 53. Zwalnianie kontekstu • ReleaseInstanceMode.BeforeCall • ReleaseInstanceMode.AfterCall • ReleaseInstanceMode.BeforeAndAfterCall
  54. 54. Durable services • Długotrwałe procesy – Wywołanie – długi czas oczekiwania - wywołanie • Trwałe zapisywane stanu (np. baza danych) – Serializacja – deserializacja – Provider (domyślny lub własny) • ID instancji – Komunikaty aktywacyjne (jeśli brak ID) – Komunikaty kooczące (usunięcie instancji) <behaviors> <serviceBehaviors> <behavior name = "DurableService"> <persistenceProvider type = "... type ... , ... assembly ... " <!-- Provider-specific parameters --> /> </behavior> </serviceBehaviors> </behaviors>
  55. 55. [Serializable] [DurableService] class MyCalculator : ICalculator { double Memory { get; set; } [DurableOperation(CanCreateInstance = true)] public double Add(double number1, double number2) { return number1 + number2; } public void MemoryStore(double number) { Memory = number; } [DurableOperation(CompletesInstance = true)] public void MemoryClear() { Memory = 0; } //Rest of the implementation }
  56. 56. Throttling • Tymczasowe piki w obciążeniu – Kolejkowanie, spłaszczenie piku • Nie działa w przypadku stałego zwiększenia obciążenia • Możliwe do konfiguracji: maxConcurrentCalls, maxConcurrentSessions, maxConcurrentInstances
  57. 57. Operacje
  58. 58. One-way • [OperationContract(IsOneWay = true)] – Przed metodą usługi – Domyślnie – false – Metoda musi zwracad void (inaczej błąd) • Wyjątki usługi nie dotrą do klienta • Błędy komunikacyjne nadal się pojawiają • Jeśli reliablesession (transport session) – wtedy jest przerywana • Najlepsza praktyka: tylko PerCall i Singleton
  59. 59. Operacje duplex • Niektóre bindingi – WSDualHttpBinding, NetTcpBinding, NetNamedPipeBinding – Nie jest standardem • Odpowiedź wywoływana przez serwis na klasie klienta – WSDualHttpBinfing - domyślnie port 80 (możliwa zmiana) • Wywołanie natychmiastowe lub referencja na poźniej IMyContractCallback callback = OperationContext.Current.GetCallbackChannel<IMyContractCallback>( ); interface ISomeCallbackContract { [OperationContract] void OnCallback(); } [ServiceContract(CallbackContract = typeof(ISomeCallbackContract))] interface IMyContract { [OperationContract] void DoSomething(); }
  60. 60. Po stronie klienta class MyCallback : IMyContractCallback { public void OnCallback( ) { ... } } IMyContractCallback callback = new MyCallback(); InstanceContext context = new InstanceContext(callback); MyContractClient proxy = new MyContractClient(context) ; proxy.DoSomething();
  61. 61. Callback • Wywoływanie callbacku w operacji usługi – Domyślnie 1 wątek ma dostęp do metod – W trakcie wywoływanej operacji lock na instancję kontekstu – Po wywołaniu callback – odpowiedź do serwera na ten sam (zablokowany) kanał • ConcurrencyMode – Single – Multiple – ok, kłopoty z synchronizacją – Reentrant – ok • Lub: metody OneWay (brak odpowiedzi)
  62. 62. Streaming • Klasyczne wywołania – buforowane po stronie serwera – Blokowanie do czasu zakooczenia przesyłania komunikatu • Streaming (wyłącznie klasa Stream) – Niektóre bindingi (TCP, IPC, Basic HTTP) – Niemożliwy do wykorzystania z message-level security <bindings> <basicHttpBinding> <binding name = "StreamedHTTP" transferMode = "Streamed„ maxReceivedMessageSize = "120000"/> </basicHttpBinding> </bindings>
  63. 63. Streaming c.d. [ ServiceContract] interface IMyContract { [OperationContract] Stream StreamReply1( ); [OperationContract] void StreamReply2(out Stream stream) ; [OperationContract] void StreamRequest(Stream stream) ; [OperationContract(IsOneWay = true)] void OneWayStream(Stream stream); }
  64. 64. Błędy
  65. 65. Podstawy • Błędy komunikacyjne i kanałów • Błędy po stronie serwisu – Izolacja błędów od klienta! • Jeśli jest sesja – automatycznie stan kanału CommunicationState.Faulted // w klasycznym .NET ok – tu CommunicationObjectFaultedException // uwaga na using!- po dispose nowa instancja proxy IMyContract obj = new MyClass( ); try { obj.MyMethod( ); } catch {} obj.MyMethod( );
  66. 66. Propagacja błędów • Ustandaryzowane – SOAP fault • FaultException<T> class Calculator : ICalculator { public double Divide(double number1, double number2) { if (number2 == 0) { DivideByZeroException exception = new DivideByZeroException(); throw new FaultException<DivideByZeroException>(exception); } return number1 / number2; } }
  67. 67. Kontrakty błędów • Każdy błąd dociera do klienta jako FaultException – Także FaultException<T> (dziedziczy po FaultException) – Wszystko co jest wymieniane musi byd w kontrakcie • [FaultContract] – Musi byd dokładnie klasa błędu – Nie może byd to nawet klasa dziedzicząca! – Może byd kilka – dla kilku typów – Nie można aplikowad dla operacji OneWay (błąd) – Nie zamyka kanału komunikacji (każdy dziedziczący po FaultException) • Kontrakt publikowany w metadanych – Klasy błędów importowane podczas generacji proxy • IErrorHandler [OperationContract] [FaultContract(typeof(DivideByZeroException))] double Divide(double number1, double number2) { ... } // jeśli typeof(Exception) -może być tylko throw Exception!
  68. 68. Debugowanie - ExceptionDetail [ServiceBehavior(IncludeExceptionDetailInFaults = true)] class MyService : IMyContract { public void MethodWithError() { throw new InvalidOperationException("Some error"); } } // --------------------------------------- MyContractClient proxy = new MyContractClient( ); try { proxy.MethodWithError( ); } catch(FaultException<ExceptionDetail> exception) { Debug.Assert(exception.Detail.Type == typeof(InvalidOperationException).ToString( )); Debug.Assert(exception.Message == "Some error") ; } // Może byd ustawiane ręcznie / w konfiguracji hosta (debugowanie istniejącego serwisu!) // Uwaga przy deployment!
  69. 69. Transakcje
  70. 70. Transakcje • Wymagane zasoby transakcyjne – WCF Resource Managers – Np. baza danych czy kolejka MSMQ, Volatile Resource Managers – http://msdn.microsoft.com/en-us/magazine/cc163688.aspx#S8 • Transakcje rozproszone – Two-phase commit i transaction manager – 1 faza: voting, 2 faza: faktyczny commit • Protokoły (wybór automatyczny) – Lightweight – app domain – OleTX – intranet – WS-Atomic Trnsaction (WSAT) - internet
  71. 71. Propagacja transakcji • Obsługują wybrane bindingi – TCP, IPC, WS http • Domyślnie – wyłączone – Konieczne włączenie po stronie klienta i serwera • Sesja – nie wymagana, ale zalecana <bindings> <netTcpBinding> <binding name = "TransactionalTCP" transactionFlow = "true" /> </netTcpBinding> </bindings>
  72. 72. Propagacja transakcji c.d. • Nie wszystkie operacje muszą obsługiwad transakcje • [TransactionFlow] – Allowed – NotAllowed – Mandatory • Operacje OneWay – błąd [ServiceContract] interface IMyContract { [OperationContract] [TransactionFlow(TransactionFlowOption.Allowed)] void MyMethod(); }
  73. 73. Transaction Manager • Nadzoruje transakcję • Lightweight Transaction Manager (LTM) – AppDomain, SQL 2005/2008 • Kernel Transaction Manager (KTM) – Vista / Windows Server 2008 – KRM: Transactional file system (TxF), Transaction registry (TxR) – Tylko jeden serwis • Distributed Transaction Coordinator (DTC) – Wykorzystywany w transakcjach rozproszonych – OleTX / WSAT • Każda transakcja najpierw zarządzana przez LTM – Jeśli więcej usług / zasobów – promocja do DTC – Jeśli zasób KRM – promocja do KTM
  74. 74. Transakcja z DTC
  75. 75. Ambient transaction • Transakcje wewnątrz thread local storage (TLS) – Transaction t = Transaction.Current; • Automatyczne przenoszenie transakcji na stronę usługi • Transaction Scope class MyService : IMyContract { [OperationBehavior(TransactionScopeRequired = true)] public void MyMethod() { Transaction transaction = Transaction.Current; Debug.Assert(transaction != null); } }
  76. 76. Przykładowy przepływ
  77. 77. Głosowanie (commit) • Deklaratywnie – Zalecane – domyślnie TransactionAutoComplete = true – Jeśli mamy strukturę try-catch, wyrzucid wyjątek dalej [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)] public void MyMethod( ) { ... } [OperationBehavior(TransactionScopeRequired = true)] public void MyMethod( ) { ... }
  78. 78. Głosowanie (kod) • Zatwierdzenie powinno byd ostatnim wywołaniem w metodzie [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = false) ] public void MyMethod( ) { try { /* Na koniec: */ OperationContext.Current.SetTransactionComplete( ); } catch { /* np. logowanie, następnie: */ throw; } }
  79. 79. Izolacja transakcji • Domyślnie – Unspecified – Wykorzystywany poziom transakcji klienta • Jeśli inny – klient musi mied zadeklarowany poziom transakcji taki sam (inaczej błąd) class MyService : IMyContract { ... } [ServiceBehavior(TransactionIsolationLevel = IsolationLevel.Unspecified)] class MyService : IMyContract { ... }
  80. 80. Klient using (TransactionScope scope = new TransactionScope()) { MyContractClient proxy1 = new MyContractClient( ); proxy1.MyMethod( ); proxy1.Close( ); MyOtherContractClient proxy2 = new MyOtherContractClient( ); proxy2.MyOtherMethod( ); proxy2.Close( ); scope.Complete( ); }
  81. 81. Instancjonowanie PerCall MyContractClient proxy = new MyContractClient( ); using(TransactionScope scope = new TransactionScope( )) { proxy.MyMethod( ... ) ; proxy.MyMethod( ... ) ; scope.Complete( ); } proxy.Close( );
  82. 82. Instancjonowanie PerSession • Domyślnie – podobnie jak PerCall – Po scope.Complete – instancja usuwana – ReleaseServiceInstanceOnTransactionComplete – ConcurrencyMode musi byd Single [ServiceBehavior(ReleaseServiceInstanceOnTransactionComplete = true)] class MyService : IMyContract { [OperationBehavior(TransactionScopeRequired = true)] public void MyMethod( ) { ... } [OperationBehavior( ... )] public void MyOtherMethod( ) { ... } }
  83. 83. „Prawdziwe” PerSession • ReleaseServiceInstanceOnTransactionComplete = false • Zapisywanie stanu – Resource Manager – jako klucz identyfikator sesji OperationContext.Current.SessionId – Volatile Resource Managers – pola obiektu instancji
  84. 84. PerSession – c.d. • Możliwe zrównanie czasu trwania sesji z czasem trwania transakcji – ReleaseServiceInstanceOnTransactionComplete = false – TransactionAutoComplete = false – Uwaga na timeout • Nie zalecane [ ServiceBehavior(TransactionAutoCompleteOnSessionClose = true) ] class MyService : IMyContract {. . . }
  85. 85. Durable Services • Stan zapisywany w bazie – Transakcja może niechcący przed tym powstrzymad • Domyślnie – zapisywanie stanu nie jest częścią transakcji • [SaveStateInOperationTransaction] – Domyślnie – false – True – aby stan był zarządzany transakcją
  86. 86. Singleton • Domyślnie – PerCall – ReleaseServiceInstanceOnTransactionComplete • Stan w Volatile Resource Managers
  87. 87. Wielowątkowośd
  88. 88. Tryby • [ServiceBehavior(ConcurrencyMode=…)+ – Single – Reentrant – Multiple • Single – Domyślny – Tylko jeden wątek na raz • Multiple – Konieczne synchronizowanie dostępu • lock { } • [MethodImpl(MethodImplOptions.Synchronized)] • W takim wypadku – niewielki zysk – Limitowane przez throttle – domyślnie 16 połączeo • Reentrant
  89. 89. Wątek UI • WPF, Silverlight – Dispatcher partial class MyForm : Form { Label m_CounterLabel; public SynchronizationContext MySynchronizationContext { get; set; } public MyForm() { InitializeComponent(); MySynchronizationContext = SynchronizationContext.Current; } void InitializeComponent() { . . . m_CounterLabel = new Label( ); . . . } public int Counter { get { return Convert.ToInt32(m_CounterLabel.Text); } set { m_CounterLabel.Text = value.ToString(); } } }
  90. 90. Synchronization Context – c.d. [ServiceContract] interface IFormManager { [OperationContract] void IncrementLabel(); } class MyService : IFormManager { public void IncrementLabel() { MyForm form = Application.OpenForms[0] as MyForm; Debug. Assert(form ! = null) ; SendOrPostCallback callback = delegate { form.Counter++; }; form.MySynchronizationContext.Send(callback, null); } } static class Program { static void Main() { ServiceHost host = new ServiceHost(typeof(MyService)); host.Open(); Application.Run(new MyForm()); host.Close(); } }
  91. 91. Wątek UI [ServiceBehavior(UseSynchronizationContext = true)] class MyService : IMyContract {. . . } • Jeśli wątek uruchamiający usługę ma Synchronization Context, automatycznie kontekst przechodzi do usługi • Form jako usługa (i tak ścisłe powiązanie) – Form jako callback – ok • Inne rozszerzenia – Np. Ustawianie priorytetów dla wywołao http://msdn.microsoft.com/en-us/magazine/cc163321.aspx
  92. 92. Operacje asynchroniczne • Specjalne pole checkbox podczas dodawania referencji • Klasycznie jak w .NET – Begin<operacja>, End<operacja> – End – blokuje – Callback – Polling – IsCompleted – Wiele wywołao – WaitAll() i IAsyncResult.WaitHandle
  93. 93. Serwisy kolejkowane
  94. 94. Serwisy kolejkowane • Dostępnośd usługi • Load leveling – skolejkowanie „piku” • Kolejkowanie niezależnych operacji biznesowych • Kompensacja (druga kolejka z wynikami) • Kolejkowanie w WCF – NetMsmqBinding – Opakowanie komunikatu SOAP w komunikat MSMQ
  95. 95. Architektura • Klient wywołuje proxy • Proxy zapisuje komunikat do kolejki • Usługa netMsmqBinding instaluje Channel Listener • Channel listener powiadamia o komunikacie – komunikat zdejmowany i przetwarzany
  96. 96. Kolejkowanie w WCF • Tylko operacje OneWay – Nie mogą zwracad wartości – Nie mogą zwracad błędów • Kolejki MSMQ – Public – pomiędzy serwerami w domenie – Private – lokalne, nie wymagają DC – Jeden endpoint = jedna kolejka • Hosting WAS – nazwa kolejki = nazwa pliku svc – address = "net. msmq: //localhost/private/WASService. svc" <endpoint address = "net.msmq: //localhost/private/MyServiceQueue" binding = "netMsmqBinding" ... />
  97. 97. Transakcje • MSMQ uczestniczy w transakcjach (opcja) – Jeśli włączone – komunikaty zapisywane na dysk – Transakcje playback – nasz kod • Publiczna kolejka i reliable messeging – Kolejka proxy – Automatyczne ponawianie wysłania komunikatu
  98. 98. Sesja i MSMQ • SessionMode.Allowed lub SessionMode.NotAllowed – brak sesji – Każdy komunikat pojedynczo • SessionMode.Required – Sessiongram – pakowanie komunikatów w „paczkę” – Zachowana kolejnośd doręczenia
  99. 99. Instancjonowanie PerCall //Klient using(TransactionScope scope = new TransactionScope( )) { MyContractClient proxy = new MyContractClient( ); proxy.MyMethod( ); //Komunikat wysłany proxy.MyMethod( ); //Komunikat wysłany proxy.Close( ); scope.Complete( ); } // Zatwierdzane • Brak przejścia transakcji na stronę usługi • Każde wywołanie osobno, osobne instancje
  100. 100. Instancjonowanie PerSession using(TransactionScope scope = new TransactionScope( )) { MyContractClient proxy = new MyContractClient( ); proxy.MyMethod(); proxy.MyMethod(); proxy.Close( ); //Skomponowano komunikat, zapis. scope.Complete( ); //Musi być za proxy.Close!! } //Pojedynczy komunikat zapisany
  101. 101. Instancjonowanie PerSession • Nie mogą mied trwającej sesji – Podobnie do PerCall • Ale - wszystkie komunikaty do tej samej instancji
  102. 102. Throttling • Po włączeniu usługi – wszystkie komunikaty na raz – Duża liczba instancji kontekstu – obciążenie • Umożliwia stopniowe przetwarzanie
  103. 103. Kiedy pojawią się problemy • Błędy – Komunikacja – Bezpieczeostwo – Quota – … • Dead-letter queue (DLQ) – Problem z doręczeniem – Nieudany commit transakcji playback – Przetwarzanie kolejki jak zwykły serwis (kontrakt musi byd ten sam / dziedziczący)
  104. 104. <! -- Client side --> <system. serviceModel> <client> <endpoint address = "net. msmq: //localhost/private/MyServiceQueue" binding = "netMsmqBinding" bindingConfiguration = "MyCustomDLQ" contract = "IMyContract" /> </client> <bindings> <netMsmqBinding> <binding name = "MyCustomDLQ" deadLetterQueue = "Custom" customDeadLetterQueue = "net.msmq: //localhost/private/MyCustomDLQ"> </binding> </netMsmqBinding> </bindings> </system. serviceModel> <! -- DLQ service side --> <system. serviceModel> <services> <service name = "MyDLQService"> <endpoint address = "net.msmq://localhost/private/MyCustomDLQ" binding = "netMsmqBinding" contract = "IMyContract" /> </service> </services> </system. serviceModel>
  105. 105. Komunikaty Poison • Komunikaty Poison – Nieustanne próby doręczenia – Zawsze błąd – Również usługa z polimorficznym kontraktem • Możliwe akcje – Drop – odrzucenie i potwierdzenie, że dostarczono – Reject – odrzucenie i NACK – Move – przeniesienie do odpowiedniej kolejki
  106. 106. Popularne wzorce • Response service – Komunikaty mogą byd jednokierunkowe – Można zapisywad odpowiedzi w innej kolejce • HTTP Bridge – Kolejki – raczej intranet – Nie interoperacyjne – Mostek WS-HTTP
  107. 107. Bezpieczeostwo (podstawy)
  108. 108. Tryby • Transport – Negocjacja (protokół), zależy od protokołu – Weryfikacja integralności treści komunikatu – Akcelerowane przez karty sieciowe • Message – Treśd komunikatu szyfrowana • Mieszane – Mix - transport do integralności i szyfrowanie hasła – Oba – uwaga na wydajnośd
  109. 109. Bindingi i tryby bezpieczeostwa
  110. 110. Intranet • Bindingi – NetTcpBinding – NetNamedPipeBinding – NetMsmqBinding • Transport security – None – Signed – tożsamośd nadawcy i integralnośd komunikatu – Encrypted and signed – dodatkowo szyfrowanie • Najczęściej – uwierzytelnienie Windows (domain / username / password) • Autoryzacja – grupy Windows <bindings> <netTcpBinding> <binding name = "TCPWindowsSecurity"> <security mode = "Transport"> <transport clientCredentialType = "Windows" protectionLevel = "EncryptAndSign" /> </security> </binding> </netTcpBinding> </bindings>
  111. 111. Intranet – c.d. • ServiceSercurityContext.Current – IsAnonymous – PrimaryIdentity – WindowsIdentity • Thread.CurrentPrincipal : IPrincipal • PrincipalPermissionMode – UseWindowsGroups – UseAspNetRoles – None, Custom • Deklaratywne wymuszanie – [PrincipalPermission(SecurityAction.Demand, Role = „Manager”)+ • Impersonacja – Możliwa, ale niezalecana
  112. 112. Internet • Bindingi – WSHttpBinding – WSDualHttpBinding • Message security – Szyfrowanie certyfikatem X509 • Certyfikat – Plik konfiguracyjny (więcej kłopotu ze zmianami) – Trusted People – zalecane • Tryb walidacji certyfikatu (certificateValidation) – PeerTrust – TrustedPeople – ChainTrust – zaufane root authority: Verisign / Thwart / … – PeerOrChainTrust <behavior name = "Internet"> <serviceCredentials> <serviceCertificate findValue = "MyServiceCert" storeLocation = "LocalMachine" storeName = "My" x509FindType = "FindBySubjectName" /> </serviceCredentials> </behavior>
  113. 113. Uwierzytelnienie // Hasło (klasycznie) MyContractClient proxy = new MyContractClient( ); proxy.ClientCredentials.UserName.UserName = "MyUsername"; proxy.ClientCredentials.UserName.Password = "MyPassword"; proxy.MyMethod( ); proxy.Close( ); // Windows (raczej nie stosowane w Internet, chociaż możliwe) <behavior name = "UsernameWindows"> <serviceCredentials> <userNameAuthentication userNamePasswordValidationMode = "Windows"/> <serviceCertificate . . . /> </serviceCredentials> </behavior>
  114. 114. Autoryzacja • Najprościej – Role Provider – Model znany z ASP.NET – Dowolne źródło danych (własna lub generowana baza) • Duplex – Odradzane, w prosty sposób autoryzacja niedostępna
  115. 115. B2B • Nie współdzielą kont – Przedstawianie się certyfikatem X509 (klient) – Dozwoleni klienci instalowani w Trusted People • Szyfrowanie certyfikatem serwera • Najczęściej nie potrzebna autoryzacja – Niewielka liczba lub jeden klient – Możliwe wykorzystanie Role Providera – identyfikator certyfikatu jako username
  116. 116. Podsumowanie
  117. 117. Programowanie Web w WCF REST, Get, Post, Delete,RSS (i HTTP)
  118. 118. Terminologia • RSS – prosty format XML dla zestawu danych • ATOM – jak RSS, ale bardziej ustrukturalizowany • Syndykacja (Syndication) – nadzbiór RSS, ATOM, inne • AJAX – DHTML + JavaScript + asynchroniczne przetwarzanie • JSON – Format danych (tablicy) w JavaScript • REST – … • POX – plain old XML (bez koperty SOAP)
  119. 119. REST • Protokół HTTP został zaprojektowany z 8 słowami • Low REST – API bazujące na GET & POST – Też tak działa przeglądarka • High REST sugeruje stosowanie 4 głównych słow – GET/PUT/DELETE/POST – CRUD dla Web • Wywoływanie usługi bez warstwy „komunikatu” czy „koperty” – …sam HTTP • Oparte na – URI do definowania endpoint (zasób) • Spacje & URITemplates – Polecenia HTTP definiują operacje • GET/PUT/DELETE/POST – Typy zawartości • XML , JSON, <mikroformaty>
  120. 120. Aplikacje REST - atrybuty • WebGet: Atrybut do oznaczania operacji które są wołane przez HTTP GET • webHttpBinding: Binding dla usług REST • webServiceHost: Klasa do hostowania usług REST • webServiceHostFactory: Klasa do hostowania usług REST które nie wymagają pliku konfiguracyjnego [OperationContract] [WebGet(UriTemplate=“/WeatherMap/{country}/{zipcode}”)] Stream GetWeatherMap(String country, String zipcode);
  121. 121. Developing REST Applications WCF & URI Spaces: URITemplate • QueryString syntax still available • URITemplate: formalism for binding URI structure to method parameters [OperationContract] [WebGet(UriTemplate=“/WeatherMap/{country}/{zipcode}”)] Stream GetWeatherMap(String country, String zipcode); http://myserver/WeatherMap/USA/98052 http://myserver/GetWeatherMap?country=USA&zipcode=98052
  122. 122. Developing REST Applications WCF & Transfer: HTTP verbs support • WebInvoke: new attribute for making a method accept any non-GET verb – PUT, DELETE, POST... [OperationContract] [WebInvoke(METHOD=“PUT”)] WeatherReport UploadWeatherReport(WeatherReport theReport);
  123. 123. Ręczne modelowanie URI • Pomoc: System.UriTemplate Uri address = new Uri(“http://localhost:2000”); UriTemplate template = new UriTemplate(“{artist}/{album}”); Uri boundUri = template.BindByPosition(address, “Northwind”, “Overdone”); UriTemplateMatch match = template.Match(address, boundUri); String bandName = match.BoundVariables[“artist”];
  124. 124. URI w kontrakcie WCF • Składnia QueryString nadal dostępna • Typ UriTemplate mapuje na parametry – Jako atrybut albo jako oddzielny typ [OperationContract] [WebGet(UriTemplate=“/Image/{bandName}/{album}”)] Stream GetAlbumImage(String bandName, String album); [OperationContract] [WebGet(UriTemplate=“/Image?name={bandName})] Stream GetMainImage(String bandName);
  125. 125. Kontrakt typu zobacz / zrób [OperationContract] [WebGet(UriTemplate=“/Image/{bandName}/{album}”)] Stream GetAlbumImage(String bandName, String album); [OperationContract] [WebInvoke(METHOD=“PUT”)] // {PUT, POST, DELETE} void AddAlbum(AlbumInfo albumInfo);
  126. 126. REST – zwracanie wartości • Typ zawartości zależy od: – Zachowanie enableWebScript (JSON) albo ustawione w klasie hostującej – Atrybutu Response.Format – Ręcznie: • WebOperationContext.Current.OutgoingResponse.Conte ntType [OperationContract] [WebGet(UriTemplate = "WeatherReport/{country}/{zipcode}/JSON", ResponseFormat=WebMessageFormat.Json)] WeatherReport GetWeatherReportWithTemplateJSON(string country, string zipcode);
  127. 127. JSON – co to jest? • JavaScript Object Notation • Format do łączenia JavaScript i obiektów – Łatwiejsze niż XML • Użycie – ASP.NET AJAX – Skrypty JS – Dynamiczny kod… var data = {“temp” : 59, “descr” : “cloudy”}; document.write (“The weather is “ + data.descr);
  128. 128. Konwencje związane z danymi [OperationContract(Name=“TestOp”)] [WebInvoke(METHOD=“PUT”)] // {PUT, POST, DELETE} String[] AddAlbum(AlbumInfo albumInfo); PUT /albumservice/AddAlbum HTTP 1.1 HOST: contoso.com <albumInfo> <Name>Hysteria</Name> <RelDate>8/3/1987</RelDate> ... </albumInfo> •XML Namespace pochodzi z kontraktu •Nazwy parametrów z sygnatury operacji
  129. 129. Zwrócenie rysunku w WCF Stream GetAlbumImage(String bandName, String album){ Stream stream; // obraz „skądś” // ustawiamy ContentType i zwracamy strumień WebOperationContext.Current.OutgoingResponse.ContentType = “image/jpeg”; return stream; }
  130. 130. WCF i syndykacja Syndykacja: Gromadzenie danych z różnych źródeł w jednym miejscu (blogi, artykuły itp.) SyndicationFeed: pojęcie „feedu” niezależne od formatu SyndicationFeedFormatter<> [ServiceKnownType(typeof(Atom10FeedFormatter))] [ServiceKnownType(typeof(Rss20FeedFormatter))] [ServiceContract] interface IPictureSyndication { [OperationContract] [WebGet(UriTemplate=“Images/{format}")] SyndicationFeedFormatter<SyndicationFeed> GetImage(String format); }
  131. 131. Kontekst bez protokołu WS=* • Konwersacja bazująca na kanale komunikacyjnym - problem • Konwencja wywołania – W tle • Binding: basicHttpContextBinding NetTcpContextBinding BasicHttpContextBinding • Behavior: – <persistenceProvider> • Ten sam co w WF  • Uwaga! Klient musi też byd świadomy kontekstu – WCF Service Host nie jest…

×