06. Zapamiętywanie stanu aplikacji - część I

06. Zapamiętywanie stanu aplikacji - część I

Autor: Piotr Gaszewski

Opublikowano: 1/6/2006, 12:00 AM

Liczba odsłon: 73238

Obiekt reprezentujący pojedynczą stronę internetową istnieje tylko w momencie zwrócenia odpowiedzi na zapytanie klienta, po czym jest natychmiast niszczony. Zapamiętywanie wartości liczbowych, znakowych, czy całych obiektów, jako jego właściwości jest więc niemożliwe (tzn. jest możliwe, ale na dłuższą metę nie przynosi żadnych, interesujących nas korzyści). Zastanawiacie się zapewnie, w jaki sposób można przechowywać obiekty, między kolejnymi zapytaniami do serwera. W rozdziale tym postaram się przedstawić kilka najbardziej popularnych technik.

W celu zrozumienia zasad działania poszczególnych metod przechowywania stanu w aplikacjach internetowych, będziemy musieli przyjrzeć się bliżej cyklowi życia tejże aplikacji. Aplikacja "żyje" tak długo, dopóki istnieją aktywne sesje w obrębie tej aplikacji. Dla wielu w Was, brzmi to zapewnie dość enigmatycznie. Wszystko rozpoczyna się w momencie, kiedy w oknie przeglądarki po raz pierwszy zostaje wyświetlona strona, wchodząca w skład naszej aplikacji. Jak zapewnie pamiętacie, aby to nastąpiło, na serwerze musi zostać uruchomiona nowa aplikacja, która z kolei wygeneruje obiekt, opisujący zawartość strony (WebForm), która zwracana jest do klienta. Po wykonaniu tej czynności obiekt ten jest natychmiast niszczony. Działanie aplikacji się jednak nie kończy. Użytkownik posiada, bowiem cały czas aktywną sesję z aplikacją. A oprogramowania znajdującego się na serwerze może korzystać jednocześnie wiele osób. Każda z nich jest posiadaczem aktywnej sesji. Okres działania aplikacji kończy się w momencie, kiedy nie istnieją dla niej żadne sesje użytkowników. Sesja kończy się w określonym, ustalonym czasie (standartowo jest to dwadzieścia minut) braku aktywności użytkownika. Środowisko uruchomieniowe stwierdza wówczas, że obiekty aplikacji nie są już używane, dochodzi, więc do ich zniszczenia (zajmuje się tym "odśmiecacz" – ang. garbage collector).

Przejdźmy teraz do właściwego tematu tego rozdziału. Dwie pierwsze metody zapamiętywania stanu aplikacji internetowej, które chciałbym zaprezentować, to przechowywanie zmiennych w obiektach sesji i aplikacji. Odbywa się to następująco:

Session["NazwaZmiennej"] = zmienna;
Application["NazwaZmiennej"] = zmienna;

Tak wygląda natomiast odczytywanie obiektów.

zmienna = (klasa_obiektu)Session["NazwaZmiennej"]
zmienna = (klasa_obiektu) Application ["NazwaZmiennej"]

W ten sposób mogą być zapisywane i odczytywane zarówno typy proste, jak i całe obiekty. W przeważającej większości przypadków odczytywania zmiennych, należy wcześniej dokonać rzutowania. Poniższy przykład pokaże różnice, a także zademonstruje możliwość wykorzystania opisanego sposobu zapamiętywania aplikacji.

Prace należy rozpocząć od stworzenia nowej aplikacji ASP.NET (File ->New -> Web Site -> ASP.NET Web Site). Następnie dodajmy do aplikacji nowy plik. Klikamy prawym przyciskiem myszy na wyświetloną w Solution Explorerze, lokalizację naszej aplikacji i wybieramy opcję: "Add New Item". Następnie, w nowo-otwartym oknie obiekt "Global Application Class". Pozostawiamy jego domyślną nazwę - "Global.asax".

Zajrzyjmy teraz do wnętrza nowego dokumentu. Przedstawia się ono następująco:

<%@ Application Language="C#" %>

<script runat="server">

   
void Application_Start(Object sender, EventArgs e) {
        // Code that runs on application startup
    }

   
void Application_End(Object sender, EventArgs e) {
        // Code that runs on application shutdown
    }

 
  void Application_Error(Object sender, EventArgs e) {
        // Code that runs when an unhandled error occurs
    }

  
 void Session_Start(Object sender, EventArgs e) {
        // Code that runs when a new session is started
    }

   
void Session_End(Object sender, EventArgs e) {
        // Code that runs when a session ends.
        // Note: The Session_End event is raised only when the sessionstate mode
        // is set to InProc in the Web.config file. If session mode is set to StateServer
        // or SQLServer, the event is not raised.
    }

</script
>

Widzimy, że plik ten zawiera metody obsługi zdarzeń, związanych z cyklem życia aplikacji ASP.NET. Dwie pierwsze metody: "Application_Start" i "Application_End" – uruchamiane są w momentach, odpowiednio rozpoczęcia i zakończenia działania aplikacji. Metoda "Application_Error" jest często wykorzystywana do obsługiwania błędów, pojawiających się w czasie działania programu. Natomiast "Session_Start" i "Session_End" związane są z procesami rozpoczęcia i zakończenia sesji, dla poszczególnych użytkowników aplikacji. Wyobraźmy sobie teraz, że pragniemy umieścić na stronie internetowej informację, ile osób korzysta jednocześnie z naszej aplikacji. Pierwszym krokiem do tego będzie modyfikacja (a raczej uzupełnienie) metody "Application_Start".

void Application_Start(Object sender, EventArgs e) {
    Application["LiczbaUzytkownikow "] = 0;
    Application["LiczbaUzytkownikow"] = (int)Application["LiczbaUzytkownikow"] + 1;
}

W momencie rozpoczęcia działania aplikacji, zerujemy zmienną, zawierającą liczbę użytkowników serwisu, a następnie zwiększamy ją o jeden. Wynika to z tego, że aby aplikacja rozpoczęła działanie przynajmniej jeden użytkownik musi spróbować się do niej odwołać. Wprowadzamy również zmiany w kolejnych metodach, zawartych w pliku Global.asax.

void Session_Start(Object sender, EventArgs e) {
    Application["LiczbaUzytkownikow"] = (int)Application["LiczbaUzytkownikow"] + 1;
}

void Session_End(Object sender, EventArgs e) {
    Application["LiczbaUzytkownikow"] = (int)Application["LiczbaUzytkownikow"] - 1;
}

W momencie wejścia na naszą stronę kolejnego użytkownika i co się z tym wiąże rozpoczęcia działania kolejnej sesji, liczba użytkowników, zapamiętywana z obiekcie aplikacji jest zwiększana o jeden. Odwrotnie – w przypadku wygaśnięcia sesji (co najczęściej związane jest, z zakończeniem wykorzystywania programu przez użytkownika) – następuje dekrementacja tej zmiennej.

Proponuje spróbować wyświetlić zawartość naszej zmiennej na ekranie. W tym celu na formatce, wchodzącej w skład aplikacji, umieszczamy kontrolkę typu "Label", a następnie uzupełniamy metodę Page_Load naszej formatki w następujący sposób:

protected void Page_Load(object sender, EventArgs e)
{
    this.Label1.Text = "Ilość gości na stronie: " + Application["LiczbaUzytkownikow"];
}

Efekt działania kodu, przy pierwszym uruchomieniu strony, powinien wyglądać następująco:

Zmienne, zapamiętywane w obiekcie aplikacji są wspólne dla wszystkich jej użytkowników w danym momencie. Natomiast te, zapisywane w sesji są (podobnie jak sama sesja) unikalne dla każdego użytkownika. Możemy sobie wyobrazić hipotetyczną sytuację, kiedy na początku użytkowania strony użytkownik podaje swoje imię i nazwisko. Dane te, wyświetlane są na kolejnych podstronach i są unikalne dla każdego użytkownika aplikacji.

Session["Imie"] = this.txtFirst_Name.Text;
Session[“Nazwisko"] = this.txtLast_Name.Text;

Label1.Text = “Nazywasz się: “ + Session["Imie"] + "" + Session[“Nazwisko"]

Gdzie, txtFirst_Name i txtLast_Name są kontrolkami typu: "TextBox".

Na zakończenie zajmijmy się przypadkiem, w którym chcemy wyłączyć dostęp do sesji dla określonych stron, wchodzących w skład naszej aplikacji. Dokonać tego możemy na dwa sposoby. W pierwszym przypadku, we właściwościach strony (na przykład, wykorzystując okno: "Properties") ustalamy wartość właściwości EnableSessionState = false. Możemy również wyłączyć obsługę sesji dla całej aplikacji. W tym przypadku dodajemy do projektu plik Web.config (robimy to w taki sam sposób, jak w przypadku Global.asax, tyle że tym razem w stosownym oknie wybieramy: "Web Configuration File"), a następnie, między znacznikami <system.web></system.web> dodajemy linijkę:

<sessionState mode="Off" />