Atslogo tīmekļu servisus ar kešu
Yo!
Sen nekas nav rakstīts... Daudz laika ir aizgājis HHH pasākuma sagatavošanās darbiem, kā arī Community Launch notikumam.
Ta kā TFS timesheet 3. daļa vēl ir rakstīšanas stadijā (1. un 2. apskatāma zem linkiem), šoreiz gribēju pieminēt vienu interesantu lietu, par ko biju piemirsis un varbūt, ka arī Jums šis liksies sen aizmirsts triks :)
Tātad problēmas pamatbūtība bija: ir serviss, kas atgriež baitu plūsmu, kas patiesībā ir Pdf formāta izdruka. Risināmā problēma izvirzīja prasību, ka servisa izsaukumu skaits ir jāsamazina, ja serviss ir izpildījies sekmīgi. Samazināt izsaukumu skaitu nozīmē neizsaukt servisu atkārtoti, ja operāciju ir bijusi sekmīga. Kopīgās diskusijās ar kolēģiem (viens no viņiem bija Andrejs) nonācām pie secinājuma, ka problēmas būtība bija uzstādīta nepareiza. Pēc pāris domu gājieniem un potenciālo nākamo problēmu apspriešanas pie klienta puses keša, mēs izsecinājām, ka pareizā problēmas nostādne ir: atvieglot servisa darbību ar keša palīdzību, neizpildot sūri grūto darbu (izdrukas ģenerācija no kristāla šablona uz Pdf plūsmu), bet gan sekmīgo atbildi kešot servera galā.
Šim nolūkam mums ērti noder WebMethod atribūta papildus iespējas.
Tātad, ja mēs vēlamies sekmīgo servisa izsaukumu iekešot, mums būs nepieciešams iestatīt CacheDuration īpašības vērtību.
Tātad scenārijs ir sekojošs: pieņemsim, ka mums ir serviss, kas saņem 2 parametris, kaut ko ar tiem izdara un atgriež atbildi.
Zemāk ir parādīts tīmekļa servisa kods:
[WebMethod (EnableSession = false, CacheDuration = 5)]
public string SessionLessOperation(int param1, string param2)
{
WriteLog ("Doing work in state less manner...");
return string.Format ("You provided in session state '{0}' and '{1}' parameters."
, param1, param2);
}
Tīmekļa servisam atbildi ir "jāpatur prātā" 5 sekundes. Lai to mēs vizuāli varētu novērtēt, izveidojam testa klientu mūsu izveidotajam servisam.
Tātad palaižam testa klientu un padarbināt nedaudz to.
No testa klienta redzams, ka patiesībā, visas darbības, kas tika izpildītas pēc 41 sekundes līdz 55 - patiesībā neizsauca nemaz tīmekļa servisa darbību, kas nozīmē, ka pieprasījums nemaz neskāra servisu un kešings notiek zemākā līmenī (Asp.Net handlera līmenī).
Nākamais jautājums, kas mani ieinteresēja ir - sesijas. Kas notiek ar sesijām, ja tīmekļa servisam tādas ir deklarētas ar EnableSession = true īpašības palīdzību.
Otra tīmekļa metode izsaktās šāda:
[WebMethod(EnableSession = true, CacheDuration = 5)]
public string SessionStateOperation(int param1, string param2)
{
WriteLog("Doing work in session state manner...");
if (Session["test-key"] == null)
{
Session["test-key"] = Guid.NewGuid();
}
return string.Format ("{0}: {1}\t{2}", Session["test-key"], param1, param2);
}
Šī metode izvada kādu patvaļīgi ģenerētu sesijas mainīgo, lai mēs pārliecinātos, ka tā ir tā pati sesija.
Testa klienta izsaukumu šāviņš:
Kā redzams, tad arī tīmekļa serviss, kas ir ieslēgta sesijas uzglabāšana tīri labi tiek galā ar servera puses kešingu.
Lai vēl konkrētāk pārbaudītu no sesijas atkarīgo servisu kešosas mehānismu ieviesīsim vēlvienu "klientu":
Btw, lai sekmīgi strādātu sesijas instance uz servera, nepietiek tikai ar tīru ģenerēto proxy klientu, pēc proxy klienta klases inicializācijas ir jāizpilda šāds kods, lai sekmīgi klients varētu uzglabāt servera ģenerētos sesijas identifikatorus (cookies):
srv.CookieContainer = new CookieContainer();
Jautājums: kas notiek ar WCF servisiem un kāds tur ir atbalsts kešingam? Ātri pārmeklējot MSDN specifikācijas, neko prātīgu uz pirmo sitienu neatradu. Tas ko ātrumā varēja izdomāt ir:
- Izmantojot HttpRuntime objekti nokļūt līdz Asp.Net kešinga objektam un izmantot to;
- Izmantot kaut kādu trešās puses kešošanas risinājumu (Enterprise Library, piemēram);
- Ieviest savu implementāciju kešošanas problēmas risinājumam, parasti tas reducējas līdz objekta Dictionary<string, object> izmantošanai;
Pirmais risinājums nav elegants ar to, ka, tas piešķir zināmu lomu IIS un HTTP terminiem tavā risinājumā. Trešais risinājums parasti beidzas ar 'quick and dirty solution' (ko es parasti gan dēvēju par 'fast non solution' :)), kas parasti neatbalsta keša atkarību mehānismus (dependency policy) vai arī keša izbeigšanās politikas (expiration policy).
However, sameklēju inetā nelielu piemēru, kas risina tieši šo problēmu ar interfeisa IOperationInvoker palīdzību.
Par šo problēmu iespējams, ka nepietika laika norealizēt pietiekoši smuki jeb arī iespēja netika izmantota pietiekoši aktīvi pirms tam, un .Net komanda nolēma risinājumu pataupīt nākamajām versijām.
Toties WCF ir daudzas citas labas īpašības :)