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.
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. 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. 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
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. 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. 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. 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
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. 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. 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. 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. 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;
}
}
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. 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. 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 { ... }
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. 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;
}
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. 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
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. 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. 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. 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. 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. 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
47. Per Call
• Bezstanowośd, skalowalnośd
– Konieczna inicjalizacja i zapis stanu
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
class MyService : IMyContract
{ ... }
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. 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. 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
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. [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. 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
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. 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. 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. 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. 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>
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. 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. 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. 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!
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
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. 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. Klient
using (TransactionScope scope = new TransactionScope())
{
MyContractClient proxy1 = new MyContractClient( );
proxy1.MyMethod( );
proxy1.Close( );
MyOtherContractClient proxy2 = new MyOtherContractClient( );
proxy2.MyOtherMethod( );
proxy2.Close( );
scope.Complete( );
}
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. 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. Singleton
• Domyślnie – PerCall
– ReleaseServiceInstanceOnTransactionComplete
• Stan w Volatile Resource Managers
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. 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. 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. 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. 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
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. 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. 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. 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. 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. 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. 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. Instancjonowanie PerSession
• Nie mogą mied trwającej sesji
– Podobnie do PerCall
• Ale - wszystkie komunikaty do tej samej
instancji
102. Throttling
• Po włączeniu usługi – wszystkie komunikaty
na raz
– Duża liczba instancji kontekstu – obciążenie
• Umożliwia stopniowe przetwarzanie
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)
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.
107. 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
109. 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
114. 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>
115. 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
116. 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
119. 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)
120. 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>
121. 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);
122. 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
123. 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);
124. 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”];
125. 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);
126. 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);
127. 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);
128. 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);
129. 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
130. 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;
}
131. 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);
}
132. 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…