Session umožňuje WCF službe uchovávať stavové informácie pre viacero interakcií klienta. Session vo WCF je postavené na iných princípoch a správa sa inak ako session v ASP.NET.
reklama
Session umožňuje WCF službe uchovávať stavové informácie pre viacero interakcií klienta. Session vo WCF je postavené na iných princípoch a správa sa inak ako session v ASP.NET.
Session vo WCF dáva do vzájomného vzťahu sériu správ posielaných medzi dvoma endpointami, čím sa vytvára vzájomná konverzácia klienta so službou. WCF session je charakterizované nasledovnými vlastnosťami:
- inicializácia a ukončenie volajúcou aplikáciou, teda klientom,
- správy doručené v rámci session sú spracované v poradí v akom boli doručené,
- session je abstraktný koncept, je implementované na úrovni binding-u pričom jednotlivé implementácie sa môžu odlišovať,
- nie je tu k dispozícii žiadne úložisko dát vzťahujúcich sa k session.
Naopak ASP.NET session je charakterizované nasledovne:
- inicializácia zo strany servera,
- požiadavky nie sú zoradené,
- je tu k dispozícii mechanizmus na ukladanie dát.
WCF session je koncept na úrovni komunikačných kanálov, preto súvisí aj s instancing-om služieb. Je tu vytvorená asociácia medzi kanálmi a inštanciami implementačnej triedy služby. Keď klient vytvorí nové proxy ku službe podporujúcej session, vytvorí sa nová nezávislá inštancia implementačnej triedy služby. Táto inštancia zostáva v pamäti počas existencie session, čím je zabezpečené uchovávanie stavových informácií v rámci session. Stavové informácie sú uchovávané v položkách (fields) inštancie.
Sessionful bindings
Sessionful bindings sú bindings, ktoré podporujú session. Zo systémových bindings session podporuje:
- WSHttpBinding,
- WSDualHttpBinding,
- WSFederationHttpBinding,
- NetTcpBinding,
- NetNamedPipeBinding.
Príklad
V príklade si ukážeme ako vytvoriť WCF službu podporujúcu session.
Service
Služba bude predstavovať počítadlo (counter) s operáciami Init, Increase a GetCount. Počítadlo bude uchovávať svoju aktuálnu hodnotu. Kontrakt služby je definovaný rozhraním ICounter, ktoré obsahuje príslušné metódy. Toto rozhranie je doplnené atribútom [ServiceContract(SessionMode = SessionMode.Required)], ktorý vyjadruje, že požadujeme podporu session na úrovni binding-u. Jednotlivé metódy rozhrania sú doplnené atribútom [OperationContract]. Vlastnosť (property) IsOneWay tohto atribútu špecifikuje či má metóda návratovú hodnotu. Vlastnosť IsInitiating resp. IsTerminating špecifikuje, či volanie metódy inicializuje resp. ukončí session. Ďalej je potrebné doplniť implementačnú triedu služby atribútom [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)], čím zabezpečíme, že pre každé nové klientské session bude vytvorená nová inštancia implementačnej triedy služby. C# kód kontraktu služby a implementačnej triedy služby bude:
using System;
using System.ServiceModel;
namespace CounterService
{
[ServiceContract(SessionMode = SessionMode.Required)]
public interface ICounter
{
[OperationContract(IsOneWay = true, IsInitiating = true, IsTerminating = false)]
void Init();
[OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = false)]
void Increase();
[OperationContract(IsInitiating = false, IsTerminating = true)]
int GetCount();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class Counter : ICounter
{
private int count;
public Counter()
{
WriteInfo("Counter()");
}
#region ICounter Members
public void Init()
{
count = 0;
WriteInfo("Init()");
}
public void Increase()
{
count++;
WriteInfo("Increase(), count=" + count);
}
public int GetCount()
{
WriteInfo("GetCount()");
return count;
}
#endregion
private void WriteInfo(string info)
{
Console.WriteLine("SessionId={0}, {1}", OperationContext.Current.SessionId, info);
}
}
}
Host
C# kód hostovacej konzolovej aplikácie bude:
using System;
using System.ServiceModel;
using CounterService;
namespace Host
{
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(CounterService.Counter)))
{
host.Open();
Console.WriteLine("Service started at base address: " + host.BaseAddresses[0]);
Console.ReadLine();
host.Close();
}
}
}
}
V konfiguračnom súbore hostovacej aplikácie nastavíme pomocou elementu <reliableSession /> podporu session. Pomocou atribútu inactivityTimeout nastavíme čas po aký bude session platné aj pri neaktivite klienta (default hodnota je 10 minút). Toto je jeden zo spôsobov ukončenia session. Session je inak ukončené pri uzavretí komunikačného kanála vytvoreného medzi klientom a službou. Konfiguračný súbor teda bude:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service behaviorConfiguration="Metadata" name="CounterService.Counter">
<endpoint address="Counter"
binding="wsHttpBinding"
bindingConfiguration="SessionfulBinding"
contract="CounterService.ICounter" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8008/" />
</baseAddresses>
</host>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="SessionfulBinding">
<reliableSession enabled="true"
ordered="true"
inactivityTimeout="00:10:00"/>
<security mode="None" />
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="Metadata">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Klient
Klientom služby bude konzolová aplikácia, k službe pristupujeme pomocou vygenerovanej proxy triedy. Klientská aplikácia čaká v cykle na stlačenie klávesy a potom volá operáciu Increase služby Counter. C# kód klienta:
using System;
using Client.Counter;
namespace Client
{
class Program
{
static void Main(string[] args)
{
using (CounterClient client = new CounterClient())
{
client.Init();
while (Console.ReadKey(true).Key != ConsoleKey.Escape)
{
client.Increase();
}
Console.Write("Count=" + client.GetCount());
//client.Increase();
Console.ReadKey(true);
}
}
}
}
V konfiguračnom súbore klienta opäť nastavíme podporu session:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<client>
<endpoint address="http://localhost:8008/Counter"
binding="wsHttpBinding"
bindingConfiguration="SessionfulBinding"
contract="Client.Counter.ICounter" />
</client>
<bindings>
<wsHttpBinding>
<binding name="SessionfulBinding">
<reliableSession enabled="true" />
<security mode="None" />
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
</configuration>
Po spustení hostovacej aplikácie a 2 klientských aplikácii môžeme vidieť podobný výsledok:

Session ID obsahuje GUID (globally unique identifier) vo forme reťazca. Volanie metódy GetCount spôsobí ukončenie session. Ak by sme sa potom pokúšali :) volať metódu Increase, dostali by sme výnimku hovoriacu o tom, že cez kanál už nemôžeme posielať správy:

Na záver si ešte ukážeme aké správy si medzi sebou vo WCF posielajú klient so službou pri použití wsHttpBinding-u. Na účel zaznamenania sieťovej komunikácie môžeme použiť utilitu SmartSniff. Pri volaní operácie Increase klient posiela službe nasledovnú správu vo formáte SOAP:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:r="http://schemas.xmlsoap.org/ws/2005/02/rm"
xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<r:Sequence s:mustUnderstand="1">
<r:Identifier>urn:uuid:2a337c90-d66e-4156-9a71-4ec6b9aba34b</r:Identifier>
<r:MessageNumber>4</r:MessageNumber>
</r:Sequence>
<a:Action s:mustUnderstand="1">http://tempuri.org/ICounter/Increase</a:Action>
<a:To s:mustUnderstand="1">http://192.168.0.2:8080/Counter</a:To>
</s:Header>
<s:Body>
<Increase xmlns="http://tempuri.org/" />
</s:Body>
</s:Envelope>
V elemente <r:Identifier> je session ID a v elemente <r:MessageNumber> je poradové číslo správy, pretože session vo WCF zabezpečuje aj doručenie správ v požadovanom poradí. Zdrojové kódy si môžete stiahnúť tu.
Ing. Marián Košťál (csharp@azet.sk)