132
Windows Communication Foundation Bartłomiej Zass ISV Developer Evangelist Microsoft

Windows Communication Foundation

Embed Size (px)

DESCRIPTION

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.

Citation preview

Page 1: Windows Communication Foundation

Windows Communication Foundation

Bartłomiej ZassISV Developer EvangelistMicrosoft

Page 2: Windows Communication Foundation

Od obiektów do usług

PolimorfizmHermetyzacjaDziedziczenie

KomunikatSchemat + kontrakt + polisaSzeroka współpraca

Położenie dowolneŚcisły związekMetadane w czasie działania

Obiektowe UsługiKomponentowe

1980 20001990

Page 3: Windows Communication Foundation

Zadania serwera aplikacyjnego

• „Pojemnik” na obiekty realizujące daną funkcjonalność– Jak pisać logikę obiektów?

• Infrastruktura: transakcje, sesje, stan…• Mechanizmy komunikacji• Skalowalność: 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ądzeń klienckich (za Wikipedia).Komputer dedykowany do wykonania określonych programów/zadań.

+ architektura

Page 4: Windows Communication Foundation

MTSKomponentyRuntime aplikacjiDeklaratywne transakcje i bezpieczeństwoAutoryzacja oparta o role

COM+ Luźno powiązane zdarzeniaKomponentyu kolejkowane„przepustnica” – nie więcej niż x komponentów

Enterprise ServicesModel programowania w kodzie zarządzalnymOparty o atrybuty, deklaratywny, konfiguracja w XML

Windows Communication Foundation• Komunikaty oparte o XML• Dowolny transport• Zorientowane na usługi• Bezpieczeństwo: Federacja, CardSpace

(dowody tożsamości)• Hosting - gdziekolwiek

Ewolucja usług aplikacyjnych

Page 5: Windows Communication Foundation

-2002 2002-2006 2006-

Problem – komunikacja…

Page 6: Windows Communication Foundation

4 podstawowe doktryny SOA

Wyraźne granice

Usługi są autonomiczne

Usługi dzielą kontrakt nie klasę

Kompatybilność określana przez

policy

Page 7: Windows Communication Foundation

Wprowadzenie do WCF

Page 8: Windows Communication Foundation

WCF: Adres, Binding, Kontrakt

Klient Usługa

KomunikatABC A B C

A B C

Adres Binding Kontrakt

(Gdzie) (Jak) (Co)

Endpoint

Endpoint

Endpoint

EncoderTransport

BasicHttp, WSHttp, WSDualHttp,

WSFederation…Context…

NetTcp, NetNamedPipe,

NetPeerTcp

NetMsmq, MsmqIntegration

Page 9: Windows Communication Foundation

WCF – standardowe bindingiBinding Interop Bezp. Sesja Trans. Duple

x 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ść | B = Oba | RS = Pewna sesja

Page 10: Windows Communication Foundation

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

Page 11: Windows Communication Foundation

WCF na jednym slajdzie

Definicja „końcó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

Page 12: Windows Communication Foundation

Kontrakt

• Definiują funkcjonalność usługi. • Atrybuty kontraktu:

– ServiceContract• OperationContract

– DataContract– FaultContract– MessageContract

• MessageBody• MessageHeader

• Zachowania kontraktu– Sesja, transakcje, sposób inicjacji…

Page 13: Windows Communication Foundation

Kontrakt

• Możliwość 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 = „…”)]

Page 14: Windows Communication Foundation

Host

• IIS + WAS (Vista+, Windows Server 2008+)– Zarządzanie, skalowalność, 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

Page 15: Windows Communication Foundation

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

Page 16: Windows Communication Foundation

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" %>

Page 17: Windows Communication Foundation

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; }}

Page 18: Windows Communication Foundation

Bindingi

• Protokół (HTTP, TCP, IPC, MSMQ)• Enkodowanie (plain text, MTOM)• Bezpieczeństwo (transport, komunikat)• …

Page 19: Windows Communication Foundation

Inne popularne bindingi

• NetPeerTcpBinding• WSFederationHttpBinding• WS2007FederationHttpBinding• MsmqIntegrationBinding• WebHttpBinding• WS2007HttpBinding

Page 20: Windows Communication Foundation

Wybór bindingu

Page 21: Windows Communication Foundation

Endpoint

• „Końcówka”, z którą możemy się komunikować– Przynajmniej jeden dla każdej usługi

• Dokładnie jeden kontrakt

Page 22: Windows Communication Foundation

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>

Page 23: Windows Communication Foundation

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>

Page 24: Windows Communication Foundation

Po stronie klienta

• Add service reference – automatycznie• SvcUtil

SvcUtil http://localhost:8000/MEX /out:Proxy.cs

• WcfTestClient. exe http: //localhost:9000/• Ręcznie - kodpublic 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; } //...}

Page 25: Windows Communication Foundation

[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(); }}

Page 26: Windows Communication Foundation

Wywoływanie usługi

MyContractClient proxy = new MyContractClient("MyEndpoint");proxy.MyMethod( );proxy.Close( );

// Można również using…

Page 27: Windows Communication Foundation

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( ); }

Page 28: Windows Communication Foundation

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ść (domyślnie) i informowanie kiedy nie

dostarczono (ponawianie, itp.)

<binding name = "ReliableTCP"> <reliableSession enabled = "true"/>

</binding>

Page 29: Windows Communication Foundation

Kolejność komunikatów• Nie powinniśmy wymagać konkretnego bindingu, ale czasem

istotna jest kolejność.

[DeliveryRequirements(TargetContract = typeof(IMyContract), RequireOrderedDelivery = true) ]

class MyService : IMyContract, IMyOtherContract { ... }

[ServiceContract] [DeliveryRequirements(RequireOrderedDelivery = true) ] interface IMyContract { ... }

Page 30: Windows Communication Foundation

Kontrakt

Page 31: Windows Communication Foundation

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

Page 32: Windows Communication Foundation

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) ;

Page 33: Windows Communication Foundation

Zgodność 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; }

Page 34: Windows Communication Foundation

Kontrakty danych

Page 35: Windows Communication Foundation

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 być dostępna także po stronie klienta

Page 36: Windows Communication Foundation

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

Page 37: Windows Communication Foundation

Zdarzenia serializacji

• Np. inicjalizacja• [OnSerializing], [OnSerialized]

[OnDeserializing], [OnDeserialized]

[DataContract]class MyDataContract{

[OnSerializing] void OnSerializing(StreamingContext context) {. . .}

}

Page 38: Windows Communication Foundation

Inne• Współdzielenie kontraktu

– Problem: ten sam typ w 2 serwisach (przestrzenie nazw)– „Reuse types in reference assemblies”

• Dziedziczenie– [KnownType], [ServiceKnownType]

// Customer : ContactContact contact = new Customer( ); ContactManagerClient proxy = new ContactManagerClient( );

// Błąd w czasie działaniaproxy.AddContact(contact) ; proxy.Close( );

// ------------------------

[DataContract][KnownType(typeof(Customer))]class Contact { ... }

[DataContract]class Customer : Contact { ... }

Page 39: Windows Communication Foundation

Współdzielenie kontraktu

• Zgodność 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;}

Page 40: Windows Communication Foundation

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

Page 41: Windows Communication Foundation

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

Page 42: Windows Communication Foundation

Wersjonowanie kontraktu

• Dodawanie nowych pól– Nadmiarowość 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

Page 43: Windows Communication Foundation

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

Page 44: Windows Communication Foundation

Sposoby instancjonowania

Page 45: Windows Communication Foundation

Kontekst

Page 46: Windows Communication Foundation

Zarządzanie kontekstem

• Tryby instancjonowania kontekstów• Per Call• Per Session• Singleton

Page 47: Windows Communication Foundation

Per Call

• Bezstanowość, skalowalność– Konieczna inicjalizacja i zapis stanu

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]class MyService : IMyContract{ ... }

Page 48: Windows Communication Foundation

[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 = 1MyService.Dispose( )MyService.MyService( )Counter = 1MyService.Dispose( )

Page 49: Windows Communication Foundation

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ść na wyjściu

• Uwaga: Load Balancer i sesja– Sticky Sessions

Page 50: Windows Communication Foundation

Per Session• Domyślny tryb• Instancja utrzymywana w pamięci

– Skalowalność

[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 {. . . }

Page 51: Windows Communication Foundation

Singleton

• Tworzony wraz ze startem procesu hosta• Sesja nie wymagana

– Po zakończeniu, nadal instancja w pamięci

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)] class MyService : IMyContract { ... }

• Możliwe przekazanie zainicjalizowanej instancji klasy do konstruktora hosta

Page 52: Windows Communication Foundation

Sesja a kontrakt

• Atrybuty gwarantujące prawidłową kolejność wywołań

[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();}

Page 53: Windows Communication Foundation

Zwalnianie kontekstu

• ReleaseInstanceMode.BeforeCall• ReleaseInstanceMode.AfterCall• ReleaseInstanceMode.BeforeAndAfterCall

Page 54: Windows Communication Foundation

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 kończące (usunięcie instancji)

<behaviors> <serviceBehaviors> <behavior name = "DurableService"> <persistenceProvider type = "... type ... , ... assembly ... " <!-- Provider-specific parameters --> /> </behavior> </serviceBehaviors></behaviors>

Page 55: Windows Communication Foundation

[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}

Page 56: Windows Communication Foundation

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

Page 57: Windows Communication Foundation

Operacje

Page 58: Windows Communication Foundation

One-way

• [OperationContract(IsOneWay = true)]– Przed metodą usługi– Domyślnie – false– Metoda musi zwracać 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

Page 59: Windows Communication Foundation

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();}

Page 60: Windows Communication Foundation

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();

Page 61: Windows Communication Foundation

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)

Page 62: Windows Communication Foundation

Streaming

• Klasyczne wywołania – buforowane po stronie serwera– Blokowanie do czasu zakończenia 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>

Page 63: Windows Communication Foundation

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);

}

Page 64: Windows Communication Foundation

Błędy

Page 65: Windows Communication Foundation

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( );

Page 66: Windows Communication Foundation

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;    }}

Page 67: Windows Communication Foundation

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 być w kontrakcie

• [FaultContract]– Musi być dokładnie klasa błędu– Nie może być to nawet klasa dziedzicząca!– Może być kilka – dla kilku typów– Nie można aplikować 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!

Page 68: Windows Communication Foundation

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 być ustawiane ręcznie / w konfiguracji hosta (debugowanie istniejącego serwisu!)// Uwaga przy deployment!

Page 69: Windows Communication Foundation

Transakcje

Page 70: Windows Communication Foundation

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

Page 71: Windows Communication Foundation

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>

Page 72: Windows Communication Foundation

Propagacja transakcji c.d.

• Nie wszystkie operacje muszą obsługiwać transakcje• [TransactionFlow]

– Allowed– NotAllowed– Mandatory

• Operacje OneWay – błąd

[ServiceContract]interface IMyContract{    [OperationContract]    [TransactionFlow(TransactionFlowOption.Allowed)]    void MyMethod();}

Page 73: Windows Communication Foundation

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

Page 74: Windows Communication Foundation

Transakcja z DTC

Page 75: Windows Communication Foundation

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);     }}

Page 76: Windows Communication Foundation

Przykładowy przepływ

Page 77: Windows Communication Foundation

Głosowanie (commit)

• Deklaratywnie – Zalecane– domyślnie TransactionAutoComplete = true– Jeśli mamy strukturę try-catch, wyrzucić wyjątek dalej

[OperationBehavior(TransactionScopeRequired = true,  TransactionAutoComplete = true)]

public void MyMethod( ) { ... }

[OperationBehavior(TransactionScopeRequired = true)] public void MyMethod( )

{ ... }

Page 78: Windows Communication Foundation

Głosowanie (kod)• Zatwierdzenie powinno być 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; }}

Page 79: Windows Communication Foundation

Izolacja transakcji

• Domyślnie – Unspecified– Wykorzystywany poziom transakcji klienta

• Jeśli inny – klient musi mieć zadeklarowany poziom transakcji taki sam (inaczej błąd)

class MyService : IMyContract { ... }

[ServiceBehavior(TransactionIsolationLevel =  IsolationLevel.Unspecified)]

class MyService : IMyContract

{ ... }

Page 80: Windows Communication Foundation

Klientusing (TransactionScope scope = new TransactionScope()){ MyContractClient proxy1 = new MyContractClient( ); proxy1.MyMethod( ); proxy1.Close( ); MyOtherContractClient proxy2 = new MyOtherContractClient( ); proxy2.MyOtherMethod( ); proxy2.Close( ); scope.Complete( );}

Page 81: Windows Communication Foundation

Instancjonowanie PerCallMyContractClient proxy = new MyContractClient( );using(TransactionScope scope = new TransactionScope( )){ proxy.MyMethod( ... ) ; proxy.MyMethod( ... ) ; scope.Complete( );}proxy.Close( );

Page 82: Windows Communication Foundation

Instancjonowanie PerSession

• Domyślnie – podobnie jak PerCall– Po scope.Complete – instancja usuwana– ReleaseServiceInstanceOnTransactionComplete– ConcurrencyMode musi być Single

[ServiceBehavior(ReleaseServiceInstanceOnTransactionComplete = true)]class MyService : IMyContract{ [OperationBehavior(TransactionScopeRequired = true)] public void MyMethod( ) { ... } [OperationBehavior( ... )] public void MyOtherMethod( ) { ... }}

Page 83: Windows Communication Foundation

„Prawdziwe” PerSession• ReleaseServiceInstanceOnTransactionComplete = false• Zapisywanie stanu

– Resource Manager – jako klucz identyfikator sesji OperationContext.Current.SessionId

– Volatile Resource Managers – pola obiektu instancji

Page 84: Windows Communication Foundation

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 {. . . }

Page 85: Windows Communication Foundation

Durable Services

• Stan zapisywany w bazie– Transakcja może niechcący przed tym

powstrzymać• Domyślnie – zapisywanie stanu nie jest

częścią transakcji• [SaveStateInOperationTransaction]

– Domyślnie – false– True – aby stan był zarządzany transakcją

Page 86: Windows Communication Foundation

Singleton

• Domyślnie – PerCall– ReleaseServiceInstanceOnTransactionComplete

• Stan w Volatile Resource Managers

Page 87: Windows Communication Foundation

Wielowątkowość

Page 88: Windows Communication Foundation

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łączeń• Reentrant

Page 89: Windows Communication Foundation

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(); } }}

Page 90: Windows Communication Foundation

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(); }}

Page 91: Windows Communication Foundation

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łań http://msdn.microsoft.com/en-us/magazine/cc163321.aspx

Page 92: Windows Communication Foundation

Operacje asynchroniczne

• Specjalne pole checkbox podczas dodawania referencji

• Klasycznie jak w .NET– Begin<operacja>, End<operacja>– End – blokuje– Callback– Polling – IsCompleted– Wiele wywołań – WaitAll() i

IAsyncResult.WaitHandle

Page 93: Windows Communication Foundation

Serwisy kolejkowane

Page 94: Windows Communication Foundation

Serwisy kolejkowane

• Dostępność 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

Page 95: Windows Communication Foundation

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

Page 96: Windows Communication Foundation

Kolejkowanie w WCF• Tylko operacje OneWay

– Nie mogą zwracać wartości– Nie mogą zwracać 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"    

... />

Page 97: Windows Communication Foundation

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

Page 98: Windows Communication Foundation

Sesja i MSMQ

• SessionMode.Allowed lub SessionMode.NotAllowed – brak sesji– Każdy komunikat pojedynczo

• SessionMode.Required– Sessiongram – pakowanie komunikatów w

„paczkę”– Zachowana kolejność doręczenia

Page 99: Windows Communication Foundation

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

Page 100: Windows Communication Foundation

Instancjonowanie PerSessionusing(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

Page 101: Windows Communication Foundation

Instancjonowanie PerSession

• Nie mogą mieć trwającej sesji – Podobnie do PerCall

• Ale - wszystkie komunikaty do tej samej instancji

Page 102: Windows Communication Foundation

Throttling

• Po włączeniu usługi – wszystkie komunikaty na raz– Duża liczba instancji kontekstu – obciążenie

• Umożliwia stopniowe przetwarzanie

Page 103: Windows Communication Foundation

Kiedy pojawią się problemy

• Błędy– Komunikacja– Bezpieczeństwo– Quota– …

• Dead-letter queue (DLQ)– Problem z doręczeniem– Nieudany commit transakcji playback– Przetwarzanie kolejki jak zwykły serwis (kontrakt musi być

ten sam / dziedziczący)

Page 104: Windows Communication Foundation

<! -- 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>

Page 105: Windows Communication Foundation

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

Page 106: Windows Communication Foundation
Page 107: Windows Communication Foundation

Popularne wzorce• Response service

– Komunikaty mogą być jednokierunkowe– Można zapisywać odpowiedzi w innej kolejce

• HTTP Bridge– Kolejki – raczej intranet– Nie interoperacyjne– Mostek WS-HTTP

Page 108: Windows Communication Foundation

Bezpieczeństwo(podstawy)

Page 109: Windows Communication Foundation

Tryby

• Transport – Negocjacja (protokół), zależy od protokołu– Weryfikacja integralności treści komunikatu – Akcelerowane przez karty sieciowe

• Message– Treść komunikatu szyfrowana

• Mieszane– Mix - transport do integralności i szyfrowanie

hasła– Oba – uwaga na wydajność

Page 110: Windows Communication Foundation

Bindingi i tryby bezpieczeństwa

Page 111: Windows Communication Foundation

Intranet• Bindingi

– NetTcpBinding– NetNamedPipeBinding– NetMsmqBinding

• Transport security– None– Signed – tożsamość nadawcy i integralność 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>

Page 112: Windows Communication Foundation

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

Page 113: Windows Communication Foundation

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>

Page 114: Windows Communication Foundation

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>

Page 115: Windows Communication Foundation

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

Page 116: Windows Communication Foundation

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

Page 117: Windows Communication Foundation

Podsumowanie

Page 118: Windows Communication Foundation

Programowanie Web w WCF

REST, Get, Post, Delete,RSS (i HTTP)

Page 119: Windows Communication Foundation

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)

Page 120: Windows Communication Foundation

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>

Page 121: Windows Communication Foundation

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);

Page 122: Windows Communication Foundation

Developing REST ApplicationsWCF & 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

Page 123: Windows Communication Foundation

Developing REST ApplicationsWCF & 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);

Page 124: Windows Communication Foundation

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”];

Page 125: Windows Communication Foundation

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);

Page 126: Windows Communication Foundation

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);

Page 127: Windows Communication Foundation

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.ContentType

[OperationContract][WebGet(UriTemplate = "WeatherReport/{country}/{zipcode}/JSON",ResponseFormat=WebMessageFormat.Json)]WeatherReport GetWeatherReportWithTemplateJSON(string country, string zipcode);

Page 128: Windows Communication Foundation

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);

Page 129: Windows Communication Foundation

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

Page 130: Windows Communication Foundation

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;}

Page 131: Windows Communication Foundation

WCF i syndykacjaSyndykacja: Gromadzenie danych z różnych źródeł w jednym miejscu (blogi, artykuły itp.)SyndicationFeed: pojęcie „feedu” niezależne od formatuSyndicationFeedFormatter<>

[ServiceKnownType(typeof(Atom10FeedFormatter))]

[ServiceKnownType(typeof(Rss20FeedFormatter))]

[ServiceContract]

interface IPictureSyndication {

[OperationContract]

[WebGet(UriTemplate=“Images/{format}")]

SyndicationFeedFormatter<SyndicationFeed>

GetImage(String format);

}

Page 132: Windows Communication Foundation

Kontekst bez protokołu WS=*• Konwersacja bazująca na kanale komunikacyjnym - problem• Konwencja wywołania

– W tle

• Binding: basicHttpContextBindingNetTcpContextBindingBasicHttpContextBinding

• Behavior:– <persistenceProvider>

• Ten sam co w WF

• Uwaga! Klient musi też być świadomy kontekstu– WCF Service Host nie jest…