De obicei intr-o aplicatie client-server folosim WCF pentru a putea comunica intre client si server. WCF este un framework destul de complex si desi este usor de integrat intr-o aplicatie, cand dorim sa facem ceva mai complex putem sa ne trezim pierduti intre tot felul de documentatii si carti despre WCF.
In acest post o sa prezint cum putem adauga in header-ul mesajului care se trimite la client un continut custom( date suplimentare).
O sa pornim de la urmatarea cerinta: fiecare mesaj care vine de la server trebuie sa vina insotit de un token unic a serverului.
O solutie la aceasta problema ar putea fi ca fiecare mesaj( contract) pe care il primim de la server sa fie incapsulat intr-o clasa de tip Response care contina tokenul nostru. Aceasta solutie este destul de buna, dar ce ne facem daca avem nevoie sa adaugam alte date pe langa token? O sa fie nevoie sa facem update imediat la clienti, servicile pe care le expunem prin WCF trebuie versionate si alte probleme de acest gen. Plus ca raspunsul pe care il primim de la server ar trebui sa contina doar datele pentru operatiea( actiunea) care vrem sa se execute. Altfel o sa fim nevoiti de fiecare data sa verificam daca raspunsul contine token-ul sau sa facem un wrapper peste apel. Toate aceste lucruri duc la o crestere a complexitati plus apare si un smel.
Toate aceste date, care contin statusul la server, tokenul de identificare si orice alte date pot sa fie adaugate in headerul mesajului. Trebuie avut doar grija ce fel de date punem. Informatile care se adauga in header trebuie sa fie informatii comune tuturor mesajelor si nu specifice unei singure operatii.
Acest comportament se obtine destul de simplu daca implementam interfata IDispatchMessageInspector. Prin intermediul acestei interfete putem sa modificam continutul unui mesaj inainte sa fie trimis la client. Avem doua metode pe care trebuie sa le implementam:
Am terminat cu serverul, aproape acelasi lucru trebuie sa il facem pe server, tot ce difera este ca in loc sa implementam interfata IDispatchMessageInspector o sa fie nevoie sa ne folosim de interfata IClientMessageInspector. Aceasta contine doua metode asemanatoare:
Enjoy!
In acest post o sa prezint cum putem adauga in header-ul mesajului care se trimite la client un continut custom( date suplimentare).
O sa pornim de la urmatarea cerinta: fiecare mesaj care vine de la server trebuie sa vina insotit de un token unic a serverului.
O solutie la aceasta problema ar putea fi ca fiecare mesaj( contract) pe care il primim de la server sa fie incapsulat intr-o clasa de tip Response care contina tokenul nostru. Aceasta solutie este destul de buna, dar ce ne facem daca avem nevoie sa adaugam alte date pe langa token? O sa fie nevoie sa facem update imediat la clienti, servicile pe care le expunem prin WCF trebuie versionate si alte probleme de acest gen. Plus ca raspunsul pe care il primim de la server ar trebui sa contina doar datele pentru operatiea( actiunea) care vrem sa se execute. Altfel o sa fim nevoiti de fiecare data sa verificam daca raspunsul contine token-ul sau sa facem un wrapper peste apel. Toate aceste lucruri duc la o crestere a complexitati plus apare si un smel.
Toate aceste date, care contin statusul la server, tokenul de identificare si orice alte date pot sa fie adaugate in headerul mesajului. Trebuie avut doar grija ce fel de date punem. Informatile care se adauga in header trebuie sa fie informatii comune tuturor mesajelor si nu specifice unei singure operatii.
Acest comportament se obtine destul de simplu daca implementam interfata IDispatchMessageInspector. Prin intermediul acestei interfete putem sa modificam continutul unui mesaj inainte sa fie trimis la client. Avem doua metode pe care trebuie sa le implementam:
- AfterReceiveRequest - metoda care este apelata automat dupa ce o cerere a ajuns pe client, dar inante ca ea sa fie executata
- BeforeSendReply - metoda care este apelata chiar inainte ca raspunsul sa fie trimis la client
internal class TokenDispatchMessageInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
request.Properties["ServerToken"] = "SomeValue";
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
}
}
Odata ce am facut acest lucru este nevoie sa ne definim un OperationBehavior sub forma unui atribut, pe care o sa il putem folosi la contractele sau operatiile pentru care avem nevoie de acest comportament. Prin intermediul interfetei IOperationBehavior, putem sa facem si alte actiuni precum validarea unei operatii. Noi avem nevoie doar sa ne inregistram inspectorul de mesaje definit mai sus( de fapt sa il adaugam in lista de message inspectors). public class TokenHeadersOperationBehaviorAttribute : Attribute, IOperationBehavior
{
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
TokenDispatchMessageInspector inspector = new TokenDispatchMessageInspector();
dispatchOperation.Parent.MessageInspectors.Add(inspector);
}
public void Validate(OperationDescription operationDescription)
{
}
}
Pentru operatiile la care avem nevoie de acest comportament, ajunge sa le decoram cu atributul nostru. "[ServiceContract]"
internal class MyService:IMyService
{
"[OperationContract]"
[TokenHeadersOperationBehaviorAttribute]
public Response OperationOne()
{
...
}
}
Urmatorul pas este sa ne declaram behaviorul nostru. Acest lucru se face din fisierul de configurare( dar se poate face si din cod):<system.ServiceModel>
<extensions>
<behaviorExtensions>
<add
name="endpointTokenMessageInspector"
type="Example.TokenDispatchMessageInspector, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"
/>
</behaviorExtensions>
</extensions>
...
<behaviors>
<endpointBehaviors>
<behavior name="tokenBehaviorMessageInspector">
<endpointMessageInspector />
</behavior>
</endpointBehaviors>
</behaviors>
...
<service name="Test" ...>
<endpoint
address="/Test"
binding="wsHttpBinding"
behaviorConfiguration="tokenBehaviorMessageInspector"
contract="Test.IMyService"
/>
</service>
</system.ServiceModel>
In acest moment avem configurat serverul. In cazul in care dupa ce faceti configurarile in fisierul de configurare, vedeti ca servicul nu pornteste, va recomand sa adaugati pe rand fiecare linie de configurare. In cazul in care configurarea la serviciu o faceti din cod, va puteti definii propiul endpointBehavior implementand interfata IEndpointBehavior.Am terminat cu serverul, aproape acelasi lucru trebuie sa il facem pe server, tot ce difera este ca in loc sa implementam interfata IDispatchMessageInspector o sa fie nevoie sa ne folosim de interfata IClientMessageInspector. Aceasta contine doua metode asemanatoare:
- BeforeSendReply - metoda apelata inainte ca un mesaj sa fie trimis la server
- AfterReceiveReply - metoda apelata dupa ce se primeste un raspuns de la server
internal class TokenDispatchMessageInspector : IClientMessageInspector
{
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
return null;
}
public void AfterReceiveReply(ref Message reply, object correlationState)
{
string serverToken = reply.Properties["ServerToken"] as string;
}
}
Pentru inregistrarea acestui comportament pe client trebuie sa face aceiasi pasi ca si pe server( definirea unui endpoint custom in care sa specificam behaviorul nostru).Enjoy!
Comments
Post a Comment