WCF je robustná technológia umožňujúca nastaviť správanie služieb tak, aby vyhovovalo naším požiadavkám. Pozrime sa čo sa dá nastaviť a ako to realizovať.
reklama
WCF je robustná technológia umožňujúca nastaviť správanie služieb tak, aby vyhovovalo naším požiadavkám. Pozrime sa čo sa dá nastaviť a ako to realizovať.
Service behavior (správanie služieb) - je komplexný pojem ktorý zoskupuje nasledovné nastavenia:
- Instancing - nastavenie spôsobu vytvárania inštancií implementačnej triedy služby,
- Concurrency - nastavenie vzťahu vlákien a inštancií,
- Throttling - nastavenie limitu súčasne existujúcich inštancií, session a volaní,
- Error handling - nastavenie spracovania chýb,
- Metadata - nastavenie poskytovania metadát,
- Session - nastavenie vytvárania session,
- Security - nastavenie zabezpečenia služby,
- Transactions - nastavenie transakčného vykonávania operácii služby.
Problematike instancing-u bola venovaná celá minulá časť seriálu (WCF - Instancing). Zabezpečiť publikáciu metadát služby sme sa naučili už v prvej časti seriálu (Začíname s WCF). Problematike session, security a transakcií budú venované samostatné časti seriálu. V rámci tejto časti sa bližšie pozrieme na concurrency, throttling a error handling.
Concurrency
Toto nastavenie popisuje správanie v prípade, že viaceré vlákna (threads) pristupujú k inštancii služby. Môžeme použiť tieto módy:
- single - v danom okamihu môže iba jedno vlákno pristupovať k inštancii služby,
- reentrant - iba jedno vlákno môže pristupovať k inštancii služby a naviac sú dovolené znovuvstupujúce spätné volania,
- multiple - viac ako jedno vlákno môže súčasne pristupovať k inštancii služby.
Pokiaľ nemáme skúsenosti s viacvláknovým programovaním alebo nemáme istotu či naša služba je thread-safe, odporúča sa použiť mód single. Najzvláštnejšie pôsobí mód reentrant, ktorý je užitočný v prípade keď služba volá inú službu, ktorá opäť volá prvú službu. Keby v tomto prípade nebol použitý mód reentrant, nastal by deadlock. Nastavenie concurrency je úzko späté s nastavením instancing-u. Treba si uvedomiť, že nastavenie concurrency nemá žiaden význam pokiaľ je instancing mód nastavený na per call. Concurrency mód nastavíme pomocou atribútu [ServiceBehavior] a jeho vlastnosti ConcurrencyMode:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single)]
Throttling
S týmto slovom som sa v IT svete nestretol pokiaľ som sa nezačal zaoberať WCF. Preto som nazrel do anglického slovníka a podľa neho throttle znamená škrtiť, stlmiť alebo regulovať. Throttling v poňatí WCF nastavuje limit množstva práce (správy, inštancie, vlákna), ktoré môže služba akceptovať. Vďaka nemu môžeme obmedziť systémové zdroje, ktoré môže služba zabrať. Môžeme nastaviť:
- maximálne množstvo súčasných volaní pre inštanciu služby,
- maximálne množstvo súčasne existujúcich sessions,
- maximálne množstvo súčasne existujúcich inštancií služby.
Throttling môžeme v konfiguračnom súbore nastaviť nasledovne:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="tb">
<serviceThrottling
maxConcurrentCalls="10"
maxConcurrentSessions="20"
maxConcurrentInstances="6" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Error handling
Problematika spracovania chýb (error handling) je vo WCF pomerne rozsiahla, budeme sa ňou zatiaľ zaoberať len okrajovo. Vznik chyby v prostredí .NET spôsobí vyvolanie výnimky. V metóde WCF služby môžeme tieto výnimky zachytiť pomocou bloku try-catch, skonvertovať ich na tzv. fault (fault kontrakt) a poslať ich späť klientovi ako SOAP fault.
Príklad
V príklade si nasimulujeme súčasný prístup viacerých klientov k službe, pričom využijeme nastavenia concurrency a throttling-u.
Service
Služba bude obsahovať iba jednu operáciu, ktorá bude mať vstup reťazec, výstupom bude taktiež reťazec. Počas vykonávania operácie služby bude zastavené vlákno na 2 sekundy. Implementačná trieda služby je doplnená atribútom [ServiceBehavior] pomocou ktorého nastavíme ConcurrencyMode a InstanceContextMode. Kód služby v C# bude:
using System;
using System.ServiceModel;
using System.Threading;
namespace Service
{
[ServiceContract]
public interface ITestService
{
[OperationContract]
string Operation(string input);
}
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.PerSession)]
public class TestService : ITestService
{
public TestService()
{
Console.WriteLine("TestService.TestService() " + DateTime.Now.ToLongTimeString());
}
#region ITestService Members
public string Operation(string input)
{
Console.WriteLine("input: " + input);
Thread.Sleep(2000);
return String.Format("start: {0}, end: {1}", input, DateTime.Now.ToLongTimeString());
}
#endregion
}
}
Host
Hostovacím prostredím pre službu bude konzolová aplikácia:
using System;
using System.ServiceModel;
using Service;
namespace Host
{
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(Service.TestService)))
{
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 parametre pre throttling (obmedzíme maximálny počet súčasne existujúcich inštancií služby na 3):
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="Service.TestService" behaviorConfiguration="metadataAndThrottling">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8001/"/>
</baseAddresses>
</host>
<endpoint address="TestService"
binding="basicHttpBinding"
contract="Service.ITestService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="metadataAndThrottling">
<serviceMetadata httpGetEnabled="true" />
<serviceThrottling maxConcurrentInstances="3" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Klient
Klientská konzolová aplikácia bude komunikovať so službou prostredníctvom proxy triedy. V cykle vytvoríme viacero vlákien a takmer súčasne začneme komunikovať so službou. C# kód klienta bude:
using System;
using System.Threading;
using Client.TestService;
namespace Client
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
RunNewThread();
Console.ReadLine();
}
private static void RunNewThread()
{
Thread thread = new Thread(new ThreadStart(UseService));
thread.Start();
}
private static void UseService()
{
using (TestServiceClient client = new TestServiceClient())
{
Console.WriteLine(client.Operation(DateTime.Now.ToLongTimeString().ToString()));
}
}
}
}
Konfiguračný súbor klienta bude obsahovať iba nastavenie endpointu:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<client>
<endpoint address="http://localhost:8001/TestService"
binding="basicHttpBinding"
contract="Client.TestService.ITestService" />
</client>
</system.serviceModel>
</configuration>
Keď spustíme hostovaciu a následne klientskú aplikáciu, v okne hostovacej aplikácie uvidíme približne:

V okne klienta uvidíme časy začiatku a konca volania operácie služby:

Dosiahnuté časy sú ovplyvnené vzájomnými nastaveniami concurrency, instancing-u a throttling-u. Pokiaľ chcete experimentovať s rôznými kombináciami týchto nastavení, zdrojové kódy si môžete stiahnúť tu.
Ing. Marián Košťál (csharp@azet.sk)