29
Applications ASP.NET avec VB.NET Gérard Frantz © Groupe Eyrolles, 2003, ISBN : 2-212-11280-7

Applications ASP.NET avec VB - eyrolles.com · Applications ASP.NET avec VB.NET 225 La solution à cet épineux problème est de stocker les données, non pas dans des variables de

  • Upload
    ledung

  • View
    239

  • Download
    0

Embed Size (px)

Citation preview

Applications ASP.NETavec VB.NET

Gérard Frantz

© Groupe Eyrolles, 2003, ISBN : 2-212-11280-7

221

C h a p i t r e 7

Gestion de l'état, lasession, les cookies

D A N S C E C H A P I T R E

� Mise en évidence du problème

� Stockage des données sur le client

� Stockage des données sur le serveur

Dans les chapitres précédents, nous avons essentiellement considéré les pages de façon indivi-duelle. Chacune d'elle effectuait un travail spécifique, les seules relations entre une page et uneautre étant un appel avec un hyperlien.

Nous avons également vu comment traiter les données d'une page dans des formulaires. AvecASP.NET, le code qui procède à l'affichage initial de la page et celui qui traite les données saisiespar l'utilisateur se trouvent dans la même page.

Chapitre 7 - Gestion de l’état, la session, les cookies

222

Nous n'avons cependant pas encore examiné comment effectuer un traitement sur plusieurspages et particulièrement comment retrouver dans le code associé à une page les données d'uneautre page.

Comme cela a été indiqué dans les chapitres précédents, le Web est par essence un systèmesans état : l'utilisateur demande une page, celle-ci est renvoyée par le serveur, puis tout estoublié ! Lors de la prochaine demande de l'utilisateur, le serveur ne se « rappellera » de rien.En d'autres termes, le serveur ne fait que répondre à des demandes ponctuelles de l'utilisateur,une par une, sans aucune connexion entre elles.

Cette situation peut vous sembler désespérée, mais heureusement l'infrastructure .NET ajoutetout un ensemble de traitements spécifiques sur cette mécanique relativement primitive, afin devous aider à construire de véritables applications Web. Certains de ces mécanismes sont auto-matiques, d'autres doivent être programmés explicitement.

On peut distinguer plusieurs situations et systèmes pour gérer l'état, c'est-à-dire faire passer lavaleur de données d'une page à une autre. Les quatre premières techniques se servent du clientpour stocker les données :

� Utiliser le ViewState, l'état d'affichage des pages Web mis en œuvre dans des sacs d'état(state bags).

� Utiliser des champs cachés.

� Passer les données par l'URL.

� Placer les données dans des cookies sur le poste de l'utilisateur.

Les techniques suivantes stockent les données sur le serveur :

� Stocker les données dans des variables de session.

� Faire de même avec des variables d'application.

� Utiliser le contexte.

� Placer les données dans le cache.

La gestion de l'état concerne deux catégories de données :

� Les valeurs des variables de l'application, principalement les variables de la classe asso-ciée à la page.

� Les valeurs des propriétés des contrôles de la page.

Applications ASP.NET avec VB.NET

223

� Mise en évidence du problèmePrenons un exemple simple pour montrer comment la gestion de l'état diffère dans les applica-tions Web de ce qu'elle est dans les applications classiques.

La page PageEtat1 présente un contrôle TextBox (txtNom) et un bouton OK (btnOK). Quand l'uti-lisateur clique sur le bouton, le contenu de la zone de saisie est recopié dans une variable declasse appelée Nom (il s'agit d'un membre de la classe associée à la page) :

' Variable contenant le nomPrivate Nom As String

Private Sub btnOK_Click(...) Handles btnOK.Click' Stocke le nom dans une variableNom = txtNom.Text

End Sub

Un second bouton sur la page (btnAfficheNom) permet d'afficher dans un contrôle Label(lblNom) le contenu de la variable Nom (figure 7-1) :

Private Sub btnAfficheNom_Click(...) Handles btnAfficheNom.Click' Affiche le contenu de la variablelblNom.Text = Nom

End Sub

Figure 7.1 • La page PageEtat1 ne conserve pas la valeur de la donnée

Chapitre 7 - Gestion de l’état, la session, les cookies

224

Le seul problème avec ce code est qu'il ne fonctionne pas comme on le souhaite : le texte n'estjamais affiché dans le label ! Si on exécute l'application pas à pas, on peut voir que la variableNom est vide lors de la dernière affectation.

Cela s'explique par le fait qu'à chaque demande d'une page de l'utilisateur, ASP.NET recrée unnouvel objet pour la gestion de la page, selon la classe qui lui est associée (dans notre exemple,la classe est appelée EtatPage1). Cet objet ne dure donc que le temps de traitement de la pagepar le serveur, grosso modo entre les événements Load et Unload de la page. Dès que la pageest retournée à l'utilisateur, l'objet correspondant est détruit et des données disparaissent(figure 7-2).

NoteL'exemple se trouve dans la page EtatPage1 du projet Etat du répertoire 07 des exemples.

Figure 7.2 • À chaque nouvelle page correspond un nouvel objet

Applications ASP.NET avec VB.NET

225

La solution à cet épineux problème est de stocker les données, non pas dans des variables declasse, mais dans une zone où elles seront retrouvées d'une page à l'autre (figure 7-3). ASP.NETpropose plusieurs techniques pour cela, qui sont présentées dans les sections suivantes.

� Stockage des données sur le clientLes techniques exposées dans cette section stockent les données sur le client. Si cela permetd'alléger la charge du serveur, les données sont transportées avec chaque demande du clientvers le serveur, et à chaque réponse du serveur.

Figure 7.3 • Les données sont stockées dans une zone spécifique

Chapitre 7 - Gestion de l’état, la session, les cookies

226

Les données d'état de la page

À chaque page est associé un état d'affichage (View State), qui stocke l'ensemble des donnéesde la page et de ses contrôles. Cet état d'affichage est implémenté dans un objet de classeStateBag (littéralement, sac d'état), qui enregistre les données sous la forme de paires de cléset de valeurs, dans un dictionnaire.

Ces données sont transportées du serveur à une page sur le poste de l'utilisateur, puis de celle-ci au serveur à nouveau, dans un champ caché du formulaire (un champ de type <inputtype=hidden>). Le contenu de ce champ correspond à l'ensemble des valeurs qui se trouventdans l'objet StateBag, codées de telle façon qu'elles soient transportables sur le protocole HTTPet qu'il ne soit pas facile de les décoder ou de les modifier.

L'état d'affichage n'est utilisable que sur la même page appelée plusieurs fois, pas entre plu-sieurs pages différentes.

On peut accéder à l'objet StateBag associé à une page grâce à la propriété ViewState de l'objetPage. La clé associée à une donnée est automatiquement créée si celle-ci n'existe pas, ou elleest remplacée dans le cas contraire. On peut ainsi écrire :

ViewState("Nom") = Value

pour stocker le contenu de Value sous le nom Nom. On pourra ensuite relire cette donnée :

Nom = ViewState("Nom")

On peut ainsi transformer la page de l'exemple précédent afin de stocker le nom, non plus dansune variable de la classe, mais dans l'objet StateBag de la page. Pour minimiser les modifica-

NotePour que l'état d'affichage soit opérationnel, il faut que la propriété EnableViewState de la page soit True.

AttentionToutes les données stockées dans le StateBag sont transmises au client. Il convient donc d'en limiter lataille. La mise en place de variables importantes dans le sac d'état peut faire grossir les pages de façonexcessive.

Applications ASP.NET avec VB.NET

227

tions, on peut remplacer la déclaration de la variable Nom par une propriété de même nom et quiutilise l'objet StateBag :

Private Property Nom() As StringGet

Nom = ViewState("Nom")End GetSet(ByVal Value As String)

ViewState("Nom") = ValueEnd Set

End Property

Ainsi, le code qui utilise la donnée Nom reste le même :

Private Sub btnOK_Click(...) Handles btnOK.Click' Stocke le nom dans une variableNom = txtNom.Text

End Sub

Private Sub btnAfficheNom_Click(...) Handles btnAfficheNom.Click' Affiche le contenu de la variablelblNom.Text = Nom

End Sub

Avec cette nouvelle version, le nom s'affiche bien quand on clique sur le bouton (figure 7-4).

Figure 7.4 • La page PageEtat1 conserve la valeur de la donnée

Chapitre 7 - Gestion de l’état, la session, les cookies

228

Les propriétés des contrôles

Le sac de propriétés référencé par la propriété ViewState de la page est utilisé par ASP.NET pourconserver les valeurs des propriétés des contrôles de la page. Il faut en fait distinguer deuxfaçons de définir la valeur d'une propriété :

� En phase de création, on peut donner des valeurs aux propriétés des contrôles à l'aide del'environnement de conception des pages de la fenêtre des propriétés, ou directementdans le code HTML. Toutes ces modifications sont stockées dans la page aspx, dans le codeHTML, principalement sous la forme d'attributs de balises.

� En phase d'exécution, les valeurs des propriétés peuvent être modifiées par des instruc-tions de code Visual Basic .NET. Par exemple :

txtNom.BackColor = Color.Yellow

Les valeurs des propriétés définies en phase de création ne sont jamais perdues. Lors de la géné-ration d'une page, chaque contrôle est créé avec les valeurs des propriétés établies initialement.

En revanche, les valeurs des propriétés modifiées par le code peuvent être perdues, selon lavaleur de la propriété EnableViewState de la page et des contrôles.

Nous allons illustrer cela à travers une page comprenant deux contrôles TextBox appeléstxtNom1 et txtNom2. Un bouton dont le texte est En jaune change la couleur de fond des deuxcontrôles, en modifiant la valeur de leur propriété BackColor :

Private Sub btnChange_Click(...) Handles btnChange.ClicktxtNom1.BackColor = Color.YellowtxtNom2.BackColor = Color.Yellow

End Sub

Un second bouton, OK, ne fait rien de particulier, si ce n'est qu'à son activation, la page estsoumise au serveur et regénérée, sans qu'aucun code spécifique ne soit exécuté sur le serveur.

Initialement, la valeur de la propriété EnableViewState de la page et des contrôles est True.Quand on clique sur le bouton En jaune, la couleur de fond des deux contrôles TextBox devientbien jaune, car le code ci-dessus a modifié cette couleur. Quand on clique ensuite sur le boutonOK, la couleur reste jaune bien qu'aucun code spécifique n'ait été exécuté sur le serveur. Cela

NoteL'exemple se trouve dans la page EtatPage2 du projet Etat du répertoire 07 des exemples.

Applications ASP.NET avec VB.NET

229

signifie que la valeur de la couleur de fond des deux contrôles a bien été placée dans le sac depropriétés et a été utilisée par ASP.NET lors de la régénération des contrôles après le clic sur lebouton OK.

Si on donne à la propriété EnableViewState du second contrôle TextBox la valeur False, et qu'onclique sur le bouton En jaune puis sur OK, le fond du premier contrôle est bien jaune (Enable-ViewState est toujours True), mais celui du second contrôle ne l'est plus (figure 7-5). L'état ducontrôle n'a pas été transmis.

Si maintenant on donne à la propriété EnableViewState de la page la valeur False, la couleurde fond des deux contrôles texte est perdue après avoir cliqué sur OK, quelle que soit la valeurde la propriété EnableViewState des contrôles. Les valeurs des propriétés des éléments de lapage modifiées par le code ne sont pas conservées d'une page à l'autre.

Figure 7.5 • L'état n'est transmis que pour le contrôle dont la propriété EnableViewState est True

NoteOn peut voir les données qui sont transmises entre le client et le serveur par l'intermédiaire du sac d'état,en affichant le code source de la page dans le navigateur du client, et en recherchant la balise <inputtype="hidden" name="__VIEWSTATE"/>. La valeur de cette balise correspond au contenu du sac d'état codé.

NoteL'exemple se trouve dans la page Prop du projet Etat du répertoire 07 des exemples.

Chapitre 7 - Gestion de l’état, la session, les cookies

230

Utilisation de champs cachés

Le sac d'état présenté précédemment stocke en fait les données dans un champ caché, sur leclient. On peut utiliser la même technique pour stocker d'autres données. Il suffit, pour cela,d'ajouter une balise de champ caché <input type="hidden"/> dans un formulaire. Lors de lagénération de la page contenant le formulaire, on peut donner une valeur au champ caché, parexemple un identificateur d'enregistrement. Quand l'utilisateur valide la page et renvoie le for-mulaire, l'application peut lire la valeur afin de retrouver l'identificateur en cours de traitement.

L'exemple suivant montre comment mettre cela en œuvre dans un formulaire, en utilisant uncontrôle serveur HTML. La page ChampCache comprend un bouton de commande et un champcaché appelé Caché (figure 7-6). Lors de l'initialisation de la page, dans le traitement de l'évé-nement Load pour la page, le champ caché est formaté avec une valeur correspondant, parexemple, à un identificateur :

Private Sub Page_Load(...) Handles MyBase.LoadIf Not IsPostBack Then

' Premier chargement, stocke l'identificateurCaché.Value = 5

End IfEnd Sub

Quand on clique sur le bouton OK, le formulaire est soumis au serveur. On peut alors récupérerla valeur stockée dans le champ caché pour réaliser les traitements nécessaires. Ici, la valeurest affiché dans un contrôle Label :

Figure 7.6 • La page ChampCache stocke une donnée dans un champ caché

Applications ASP.NET avec VB.NET

231

Private Sub btnVoir_Click(...) Handles btnVoir.Click' Relit l'indentificateurlblID.Text = Caché.Value

End Sub

Si vous affichez le code source de la page à partir du navigateur, vous pouvez y voir la lignesuivante. L'utilisateur lambda ignore ce champ, mais l'expert peut facilement le voir :

<input name="Caché" id="Caché" type="hidden" value="5" />

Passage de données par l'URL

Une autre technique de passage des données d'une page à l'autre consiste à les placer dansl'URL, dans l'adresse de la page à appeler.

Quand l'utilisateur clique sur un lien ou sur un bouton d'un formulaire, l'application ajoute desparamètres à l'URL correspondante. Le format d'une URL avec paramètres est le suivant :

URL?nom1=valeur1&nom2=valeur2

L'ensemble des paramètres est placé à la fin de l'URL, après un point d'interrogation. Chaqueparamètre est constitué d'un nom et d'une valeur, séparés par un signe =. Les paramètres sontséparés entre eux par un signe &.

Le nom et la valeur des paramètres placés dans l'URL sont soumis à certaines restrictions. Il nepeut notamment pas y avoir de caractères accentués ou d'espaces. On peut utiliser la méthodeUrlEncode de l'objet HttpServerUtility retournée par la propriété Server de la page. Cetteméthode prend en paramètre une chaîne de caractères et retourne la même chaîne, dans laquelleles caractères interdits ont été codés. La méthode UrlDecode effectue l'opération inverse.

La page appelée par l'URL peut récupérer ces données à l'aide de la méthode QueryString del'objet HttpRequest retournée par la propriété Request de la page.

Les exemples de cette section et des suivantes mettent en œuvre une page de saisie d'un nom,SaisieNom. Cinq boutons permettent d'appeler une autre page avec une méthode de passagedu nom différente (figure 7-7).

NoteL'exemple se trouve dans la page ChampCache du projet Etat du répertoire 07 des exemples.

Chapitre 7 - Gestion de l’état, la session, les cookies

232

Quand on clique sur le premier bouton, Affiche avec URL, le code suivant est exécuté pourconstruire l'URL avec ses paramètres :

Private Sub btnOKURL_Click(...) Handles btnOKURL.ClickResponse.Redirect("AfficheNomURL.aspx?Nom=" & Server.UrlEncode(txtNom.Text))

End Sub

Ce code utilise la méthode UrlEncode. Le texte de la zone de saisie est ici Gérard Frantz. Lerésultat de l'appel de la méthode UrlEncode(txtNom.Text) est : G%c3%a9rard+Frantz. Le carac-tère accentué est codé, ainsi que l'espace.

La page appelée, AfficheNomURL, récupère le nom à partir de l'URL grâce à la méthode Query-String, puis l'affiche dans la page (figure 7-8) :

Private Sub Page_Load(...) Handles MyBase.LoadlblNom.Text = Request.QueryString("Nom")

End Sub

Figure 7.7 • La page de saisie d'un nom permet d'appeler d'autres pages et de leur passer des données

Applications ASP.NET avec VB.NET

233

Stockage des données dans des cookies

Un cookie est du texte stocké sur le poste du client. Il est généralement enregistré à la demandedu serveur, par l'intermédiaire de la propriété Cookies de l'objet HttpResponse retourné par lapropriété Response de la page. Il peut être lu à travers la propriété Cookies de l'objet HttpRe-quest retourné par la propriété Request de la page.

Pour écrire un cookie, qui est un couple nom-valeur, il suffit de lui donner une valeur, en indi-quant son nom comme paramètre de la collection Cookies. Si le cookie existait déjà, il estremplacé, dans le cas contraire, il est créé :

sResponse.Cookies("MonCookie").Value = "La valeur"

Figure 7.8 • Affichage du nom après passage par l'URL

NoteL'exemple se trouve dans les pages SaisieNom et AfficheNomURL du projet Etat du répertoire 07 desexemples.

NoteUn cookie ne contient que du texte et il ne peut être atteint que par l'application (le site Web) qui l'a écrit.Contrairement à des croyances bien établies, un cookie n'est donc pas dangereux, dans la mesure où il estpassif et ne correspond pas à du code. Les sites Web utilisent souvent des cookies pour mémoriser le faitque l'utilisateur est passé par une page, et pour éventuellement stocker des informations liées à cetutilisateur (par exemple ses goûts, déduits de son parcours dans le site). Cela permet d'ajuster le contenudes pages du site lors d'une visite ultérieure.

Chapitre 7 - Gestion de l’état, la session, les cookies

234

Un cookie écrit de cette façon n'est pas permanent : il n'existe qu'en mémoire, donc pendant ladurée de l'application. Il disparaîtra quand celle-ci s'arrêtera.

Pour rendre un cookie permanent, il faut indiquer une date d'expiration. Par exemple :

Response.Cookies("MonCookie").Value = "La valeur"Response.Cookies("MonCookie").Expires = #1/1/2030#

Le cookie sera alors écrit sur le disque de l'utilisateur et y restera jusqu'à la date d'expirationou jusqu'à ce qu'il soit effacé.

On peut lire un cookie en utilisant la même collection Cookies, mais appliquée à l'objet HttpRe-quest. Voici le code qui relit le cookie écrit précédemment :

MonCookie = Request.Cookies("MonCookie").Value

Si le cookie existait dans cette application, sa valeur est retournée. Dans le cas contraire, lavaleur de retour est une chaîne de caractères vide.

L'ensemble des cookies d'une application est transmis avec chaque demande de l'utilisateur. Ilest donc préférable de ne placer que de petites quantités de données dans les cookies, afin dene pas grossir la trame HTTP circulant sur le réseau, d'autant plus que la taille d'un cookie estelle-même limitée.

NoteL'emplacement précis des cookies dépend du navigateur utilisé. Sous Windows XP, par exemple, InternetExplorer place les cookies dans des fichiers texte situés dans le répertoire Cookies des données del'utilisateur.

NoteL'utilisation de cookies peut être désactivée sur le poste de l'utilisateur. Si le fonctionnement de votreapplication dépend de leur emploi, il faut soit disposer d'une méthode alternative, soit avertir l'utilisateurque l'application ne fonctionnera pas correctement avec sa configuration.

L'application peut savoir si le navigateur autorise les cookies en interrogeant la propriété Cookies de l'objetHttpBrowserCapabilities, retourné par la propriété Browser de Request : Request.Browser.Cookie est Truesi le navigateur autorise les cookies, False dans le cas contraire.

Applications ASP.NET avec VB.NET

235

La page exemple SaisieNom (figure 7-7) dispose d'un bouton Affiche avec cookie. Quand l'uti-lisateur clique dessus, le contenu du champ de saisie est placé dans un cookie temporaireappelé Nom. L'application est ensuite redirigée vers une autre page, à l'aide de la méthode Redi-rect de l'objet HttpResponse :

Private Sub btnOKCookie_Click(...) Handles btnOKCookie.ClickResponse.Cookies("Nom").Value = txtNom.Text' Supprimez le commentaire de la ligne suivante pour rendre le cookie permanent'Response.Cookies("Nom").Expires = #1/1/2030# Response.Redirect("AfficheNomCookie.aspx")

End Sub

La page AfficheNomCookie affiche le texte lu dans le cookie (figure 7-9) :

Private Sub Page_Load(...) Handles MyBase.LoadlblNom.Text = Request.Cookies("Nom").Value

End Sub

Figure 7.9 • Affichage du nom après passage par cookie

NoteL'exemple se trouve dans les pages SaisieNom et AfficheNomCookie du projet Etat du répertoire 07 desexemples.

Chapitre 7 - Gestion de l’état, la session, les cookies

236

� Stockage des données sur le serveurToutes les techniques présentées précédemment stockent les données sur le poste du client.Celles de cette section les placent sur le serveur. Cela présente quelques avantages :

� Les données ne sont jamais visibles par le client.

� Elles ne circulent pas sur le réseau et ne l'encombrent donc pas.

� Elles ne sont pas liées au poste utilisé par le client, comme c'est le cas pour les cookies(si l'utilisateur utilise un autre poste, il ne dispose pas de ses cookies).

� Leur accès est plus rapide, puisqu'elles se trouvent déjà sur le serveur.

Le stockage des données sur le serveur présente également quelques inconvénients :

� Les données occupent de la place sur le serveur, ce qui peut devenir ennuyeux si beaucoupd'utilisateurs accèdent à l'application.

� L'utilisateur peut être lié au serveur sur lequel se trouvent les données, bien qu'ASP.NETpropose des solutions pour cela.

Les variables d'application

Une variable d'application est conservée dans un objet particulier, de classe HttpApplication,retourné par la propriété Application de la page. Cet objet comprend des données liées à uneapplication. Au fait, qu'est-ce qu'une application Web ? Il s'agit de l'ensemble des fichiers,pages, gestionnaires, modules et code situés dans un répertoire virtuel et ses sous-répertoiressur un serveur Web donné.

Pour créer une variable d'application, il suffit de la nommer et de lui donner une valeur, un peucomme pour les cookies présentés plus haut :

Application("NomVariable") = "Valeur variable"

Si la variable du nom indiqué existait déjà, sa valeur est remplacée, sinon elle est créée.

L'utilisation de variables d'application est donc extrêmement simple. Il faut cependant fairequelques remarques :

� Une variable d'application est vue par tous les utilisateurs de l'application. Il ne faut doncpas y stocker des données spécifiques à un utilisateur, mais plutôt des données communesà toute l'application, par exemple le nom de la société ou une table de taux de TVA.

Applications ASP.NET avec VB.NET

237

� Les variables d'application sont stockées dans le serveur Web qui les crée. Dans le casd'une ferme de serveurs (plusieurs serveurs qui jouent des rôles semblables), la demanded'un utilisateur peut être dirigée vers un serveur ou un autre selon leur charge. Une appli-cation peut donc ne pas disposer des données créées par la même application sur un autreserveur.

� Lors de la modification de la valeur d'une variable d'application, il existe un risque qued'autres utilisateurs effectuent un changement de la même variable au même moment. Ilconvient donc de synchroniser l'accès à ces variables, comme cela est montré dansl'exemple suivant.

On place donc généralement dans les variables d'application des données en lecture seule. Cesvariables sont alors utilisées comme une sorte de cache pour des données qui ne varient pasou peu pendant la durée de vie de l'application.

Il faut cependant bien initialiser les variables d'application quelque part. Cela peut être faitquand l'application démarre, en plaçant du code spécifique dans le fichier global.asax del'application qui est ajouté à un projet Web par Visual Studio .NET lors de sa création. Ce fichiercomprend des données et du code globaux à l'application. On peut notamment y ajouter desprocédures qui seront appelées par le serveur Internet quand certains événements se produi-ront. Il suffit, pour cela, de dériver une classe de la classe HttpApplication et d'y écrire lesprogrammes nécessaires. Pour gérer les variables application, on peut écrire du code dans lesprocédures suivantes :

� Init et Application_OnStart sont appelées au démarrage de l'application. On y insèredonc généralement le code d'initialisation des variables.

� Dispose et Application_OnEnd sont appelées quand l'application se termine.

On peut remarquer qu'il existe deux procédures pour le démarrage et l'arrêt de l'application.Les constructeurs et destructeurs Init et Dispose sont appelés pour chaque objet HttpAppli-cation créé, tandis que les procédures Application_OnStart et Application_OnEnd sontappelées à la première création. Il est donc généralement préférable d'initialiser les donnéesdans le constructeur Init.

NoteUne application démarre la première fois qu'un utilisateur appelle une page qui en fait partie. Si le serveurWeb est arrêté, elle l'est aussi. D'autre part, si le fichier global.asax est modifié, l'application est arrêtéepuis redémarrée.

Chapitre 7 - Gestion de l’état, la session, les cookies

238

La page AfficheNomApplication affiche une donnée placée dans une variable Applicationappelée Nom par la page appelante, SaisieNom. Celle-ci exécute le code suivant lors du clic surle bouton Affiche avec application :

Private Sub btnOKApplication_Click(...) Handles btnOKApplication.ClickApplication.Lock()Application("Nom") = txtNom.TextApplication.UnLock()Response.Redirect("AfficheNomApplication.aspx")

End Sub

On peut remarquer dans ce code que l'affectation de la valeur à la variable Application estaccompagnée d'un appel aux méthodes Lock puis UnLock. Lock verrouille l'objet Applicationafin d'éviter qu'une modification y soit effectuée en même temps par un autre thread.

La page AfficheNomApplication affiche la valeur stockée dans la variable Application lors deson chargement :

Private Sub Page_Load(...) Handles MyBase.Load' Donnée initialiée par la page appelantelblNom.Text = Application("Nom")

' Données initialisées dans Global.asaxlblInit.Text = Application("Init")lblOnStart.Text = Application("OnStart")

End Sub

Vous pouvez remarquer que le code de traitement de l'événement Load affiche également lesvaleurs de deux autres variables (figure 7-10). Celles-ci ont été initialisées dans des procéduresévénement de Global.asax :

Public Class GlobalInherits System.Web.HttpApplication

AttentionL'appel à la méthode Lock verrouille l'objet Application de façon globale. Les autres pages quiappelleraient cette même méthode seraient bloquées. Il convient donc de recourir à UnLock aussirapidement que possible et de n'effectuer que des traitements courts entre les deux requêtes.

Applications ASP.NET avec VB.NET

239

Public Overrides Sub Init()Application("Init") = "Donnée initialisée dans Init"

End Sub

Sub Application_OnStart(ByVal sender As Object, ByVal e As EventArgs)Application("OnStart") = "Donnée initialisée dans Application_OnStart"

End SubEnd Class

Les variables partagées

L'utilisation de l'objet Application pour conserver des données était courante dans les versionsprécédentes d'ASP. Elle présente cependant quelques inconvénients, particulièrement le fait queles données n'y sont pas typées, ce qui allonge les temps de traitement lorsqu'on y accède.

On pourrait être tenté d'utiliser des variables d'instance de l'objet Application (appelé Globalpar défaut) déclaré dans Global.asax. Cela n'est cependant pas possible, car il peut exister plu-sieurs objets Application créés à partir de la classe Global. Quand une page est appelée sur leserveur, ASP.NET peut, soit fabriquer un nouvel objet Global, soit utiliser un objet existant. Onne peut donc pas avoir de certitude sur l'objet Global employé par une page, et ses variablesd'instance ne peuvent donc pas être mémorisées d'un appel à l'autre.

Il est cependant possible de déclarer des variables partagées dans la classe Global avec le mot-clé Shared. Une telle variable s'utilise indépendamment de la création d'un objet, elle est doncglobale à l'application.

Figure 7.10 • Affichage du nom après passage par une variable Application

Chapitre 7 - Gestion de l’état, la session, les cookies

240

Voici, par exemple, une variable déclarée dans Global.ascx, dans la classe Global :

Public Class GlobalInherits System.Web.HttpApplication

Public Shared Nom As String

La variable Nom peut alors être valorisée dans une page, comme dans la page SaisieNom à lasuite d'un clic sur le bouton Affiche avec variable Shared :

Private Sub btnOKShared_Click(...) Handles btnOKShared.ClickSyncLock Me

Global.Nom = txtNom.TextEnd SyncLockResponse.Redirect("AfficheNomShared.aspx")

End Sub

Le problème de l'accès simultané à la donnée par plusieurs threads se pose à nouveau. Il estréglé ici en plaçant le code qui accède à la donnée dans une section de synchronisation, ce quigarantit qu'un seul thread peut exécuter la section à la fois.

L'utilisation de la donnée se fait dans une autre page, AfficheNomShared (il n'est pas nécessairede synchroniser l'accès à la donnée en lecture seule, figure 7-11) :

Figure 7.11 • Affichage du nom après passage par une variable partagée

Applications ASP.NET avec VB.NET

241

Private Sub Page_Load(...) Handles MyBase.LoadlblNom.Text = Global.Nom

End Sub

Les variables de session

Si les variables d'application sont intéressantes pour stocker les données d'une application,elles ne permettent pas de distinguer un utilisateur d'un autre. Les variables de session répon-dent à cette insuffisance, car elles sont associées à l'utilisateur courant.

La notion de session

Pour mettre en œuvre les variables de session, ASP.NET définit une notion de session qui com-prend l'ensemble des actions d'un utilisateur dans une application. Une session est reconnuepar un identificateur de session créé par ASP.NET. Il s'agit d'une chaîne de caractères de 120bits (par exemple, 302dvbynpstxl3i0rugg1b45), dont l'unicité est garantie grâce à l'utilisationd'un algorithme spécifique. De plus, la structure de cette chaîne est non triviale, ce qui évitequ'elle soit manipulée à l'insu du système (par exemple, pour se faire passer pour quelqu'und'autre).

Quand un nouvel utilisateur appelle une page d'une application ASP.NET pour la première fois,un nouvel identificateur lui est attribué. Celui-ci accompagne ensuite toutes les réponses dusystème et les demandes de l'usager, ce qui permet de l'identifier. Deux techniques peuventêtre utilisées pour cela : un cookie particulier enregistré sur le poste de l'utilisateur, ou l'inclu-sion de l'identificateur dans l'URL, essentiellement si les cookies ne sont pas autorisés par lenavigateur de l'utilisateur.

Pour accéder aux informations d'une session, la classe Page expose une propriété, Session, quiretourne une référence à un objet HttpSessionState. Celui-ci dispose de propriétés et deméthodes, dont la propriété SessionID qui renvoie l'identificateur de session courant. On peutécrire, pour placer l'identificateur de session dans un contrôle label appelé lblSessionID :

lblSessionID.Text = Session.SessionID

Le résultat est une chaîne de caractères comprenant l'identificateur de session (voir l'exemplesuivant).

La configuration de la façon dont la session fonctionne se fait dans le fichier Web.config, situédans le répertoire d'une application Web. Il s'agit d'un fichier XML comprenant, entre autres,une balise appelée sessionState qui fait partie de la section system.web du fichier. Cette balisecomprend plusieurs attributs qui définissent les caractéristiques de la session (tableau 7-1).

Chapitre 7 - Gestion de l’état, la session, les cookies

242

Voici le contenu initial de cette section, tel qu'il est généré par Visual Studio :

<configuration><system.web>

...<sessionState

mode="InProc"stateConnectionString="tcpip=127.0.0.1:42424"sqlConnectionString="data source=127.0.0.1;user id=sa;password="cookieless="false" timeout="20"

/>...

</system.web> </configuration>

Quand l'attribut cookieless a sa valeur par défaut False, le SessionID est transmis sur le postede l'utilisateur par l'intermédiaire d'un cookie. En revanche, si on donne à cookieless la valeurTrue, le SessionID est transmis dans l'URL, sous la forme d'un pseudo-répertoire dont le nomest la valeur de l'identificateur.

Tableau 7-1 • Les attributs de la section system.web du fichier web.config.

Attribut Signification

cookieless Indique si des cookies sont utilisés pour transmettre l'identificateur de session sur le poste du client (valeur False) ou l'URL (valeur True)

Mode Désigne l'emplacement des données de la session (notamment les variables). Voir ci-dessous.

stateConnectionString Il s'agit d'une chaîne qui identifie le serveur utilisé si mode vaut StateServer.

sqlConnectionString Chaîne qui identifie le serveur SQL utilisé si mode vaut SQLServer.

Timeout Détermine le temps d'inactivité en minutes au-delà duquel la session est automatiquement terminée.

NoteLe fichier Web.config est créé par Visual Studio lors de la création d'une nouvelle application Web. Vouspouvez double-cliquer dessus dans l'explorateur de solutions pour en afficher ou en modifier le contenu.

Applications ASP.NET avec VB.NET

243

L'attribut mode indique l'emplacement de stockage des variables. La modification de la valeurde cet attribut peut avoir une influence sur les performances et sur la disponibilité des donnéesde session. Les valeurs possibles sont les suivantes :

� Off, les données de session ne sont pas gardées. Les variables de session ne doivent doncpas être utilisées si mode a cette valeur.

� InProc, les données de session sont stockées en mémoire sur le serveur. Cette valeurdonne les meilleures performances (il s'agit d'ailleurs de la valeur par défaut), mais nepermet pas de conserver les données en cas de panne ou d'utilisation de plusieurs ser-veurs ou processus.

� StateServer, les données de session sont gardées sur le serveur identifié par la valeur destateConnectionString. Cette chaîne doit comprendre l'adresse du serveur suivie du portà utiliser, qui est par défaut 42424. La valeur par défaut, tcpip=127.0.0.1:42424, indiqueque les données sont stockées sur le serveur local (l'adresse IP 127.0.0.1 identifie leserveur local).

� SQLServer, les données de session sont stockées sur le serveur SQL Server identifié parla valeur de sqlConnectionString. Il s'agit d'une chaîne de connexion à SQL Server.

Les deux dernières options sont particulièrement intéressantes et n'existaient pas dans les ver-sions précédentes d'ASP. Elles permettent de partager les données de session entre plusieursprocessus.

La valeur StateServer indique que les données de la session sont placées sur le serveur spécifiépar stateConnectionString (un serveur d'état). On peut alors envisager deux configurations :

� Il n'existe qu'un serveur Web, mais plusieurs processus peuvent faire fonctionner la mêmeapplication. L'utilisation de cette valeur permet de ne pas lier un utilisateur à un processusparticulier. La valeur InProc ferait que, si l'utilisateur était connecté à un processus diffé-rent d'une page à l'autre, les valeurs de ses variables de session seraient perdues.

� Quand plusieurs serveurs Web sont utilisés pour la même application (on parle de fermede serveurs), le serveur d'état peut être commun à l'ensemble des serveurs Web. De cettefaçon, les demandes d'un utilisateur ne sont pas liées à un serveur physique particulieret la répartition de charge entre les serveurs peut être pleinement exploitée.

AttentionSi l'attribut cookieless a sa valeur par défaut False et que les cookies ne sont pas opérationnels sur leposte de l'utilisateur, l'identificateur de session et donc les valeurs des variables ne seront pas mémorisés.

Chapitre 7 - Gestion de l’état, la session, les cookies

244

La valeur SQLState de l'attribut mode permet d'aller encore plus loin, puisque les données desvariables d'application sont placées sur un serveur SQL Server. De cette façon, même si unserveur Web tombe en panne, les données ne sont pas perdues.

Le dernier attribut de la balise sessionState, timeout, indique le temps d'inactivité, en minutes,après lequel la session est fermée. Par défaut, cette valeur est de vingt minutes. La fermetured'une session permet de libérer toutes les données qui lui sont associées. Si l'application gèredes données sensibles, comme un compte en banque, il peut être préférable de diminuer cettevaleur, afin de ne pas garder en mémoire des données concernant un utilisateur qui n'utiliseplus l'application. On peut d'ailleurs forcer une fin de session, en appelant la méthode Abandon :

Session.Abandon

Cela peut être effectué, par exemple, en réponse à un clic de l'utilisateur sur un bouton de décon-nexion placé sur la page. Après la fermeture d'une session, automatiquement ou manuellement,toutes ses données sont détruites.

Les variables de session

Comme les variables d'application, les variables de session sont simplement fabriquées en lesnommant : si la variable existe, elle est utilisée, sinon elle est créée. Pour donner une valeur àla variable de session Nom, on peut simplement écrire :

Session("Nom") = "Nouvelle valeur"

L'initialisation des variables de session peut se faire dans une procédure Session_OnStart (ouSession_Start) et Session_OnEnd permet d'effectuer les traitements de fin de session. Ces deuxprocédures doivent être écrites dans le fichier global.asax, comme cela a été expliqué dans lasection relative aux variables d'application.

La page AfficheNomSession affiche une variable de session initialisée lors de la saisie du nomde l'utilisateur dans la page SaisieNom. Elle affiche également la valeur d'une variable initialiséedans la procédure Session_OnStart (figure 7-12).

NoteIl n'est pas nécessaire de mettre en œuvre un mécanisme de synchronisation pour les variables de session,car elles ne sont normalement rejointes que par un seul thread, n'étant liées qu'à un seul utilisateur.

Applications ASP.NET avec VB.NET

245

La valorisation de la variable à la suite de la saisie du nom est effectuée par le code suivant :

Private Sub btnOKSession_Click(...) Handles btnOKSession.ClickSession("Nom") = txtNom.TextResponse.Redirect("AfficheNomSession.aspx")

End Sub

L'initialisation des variables dans global.asax est :

Sub Application_OnStart(ByVal sender As Object, ByVal e As EventArgs)Application("OnStart") = "Donnée initialisée dans Application_OnStart"

End Sub

Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)Session("Start") = "Donnée initialisée dans Session_Start"

End Sub

Enfin, l'affichage des variables est réalisé par le code suivant :

Private Sub Page_Load(...) Handles MyBase.LoadlblNom.Text = Session("Nom")lblSessionID.Text = Session.SessionIDlblSession.Text = Session("Start")lblSession1.Text = Session("OnStart")

End Sub

Figure 7.12 • Affichage de variables de session

Chapitre 7 - Gestion de l’état, la session, les cookies

246

Le contexte

La propriété Context d'une page retourne l'objet HttpContext associé à la page. Celui-ci fournitdes informations sur la requête HTTP ayant provoqué son appel. Parmi les membres de la classeHttpContext, la propriété Handler donne accès à un objet HttpHandler qui représente la pageà l'origine de l'appel. Cela permet d'accéder à ses données.

Pour que le contexte permette de récupérer les données de la page précédente, il faut quel'appel de la page se fasse à l'aide de la méthode Server.Transfer et non pasResponse.Redirect.

L'utilisation du contexte peut se faire en « castant » la propriété Handler en un type correspon-dant à la page appelante. La ligne suivante permet d'accéder à la propriété Nom définie dans lapage SaisieNom :

Private Sub Page_Load(...) Handles MyBase.LoadlblNom.Text = CType(context.Handler, SaisieNom).Nom

End Sub

Voici le code de la page SaisieNom (figure 7-13) :

' Propriété Nom pour le contextePublic ReadOnly Property Nom() As String

GetReturn txtNom.Text

End GetEnd Property

Private Sub btnOKContext_Click(...) Handles btnOKContext.Click' Utilise Server.Transfer au lieu de Response.RedirectServer.Transfer("AfficheNomContext.aspx")

End Sub

NoteLes données du contexte ne sont valides que pour la requête en cours. Elles sont donc perdues lors de larequête suivante.

Applications ASP.NET avec VB.NET

247

Le cache

Le cache d'ASP.NET est un lieu de stockage de données qui peut être utilisé à la fois pour cacherdes pages, c'est-à-dire les mémoriser afin d'éviter de les régénérer à chaque demande, et pourenregistrer des données. Pour le stockage de données, le cache ressemble donc à l'objet Appli-cation dans la mesure où les valeurs qui y sont placées sont privées à l'application. Mais lecache dispose également de mécanismes complémentaires qui permettent de contrôler la duréede vie des données qu'il contient en libérant la mémoire quand elle n'est pas utilisée, ou deconditionner les données à des ressources externes.

Placer des données dans le cache se fait très simplement, comme pour l'objet Application :

Private Sub btnOKCache_Click(...) Handles btnOKCache.Click Cache("Nom") = txtNom.Text Response.Redirect("AfficheNomCache.aspx")End Sub

On peut également utiliser les méthodes Insert et Add de l'objet Cache pour ajouter des donnéesdans le cache. Ces méthodes peuvent recevoir des paramètres complémentaires permettant dedéfinir, notamment, la durée de vie des données.

L'obtention des données du cache se fait tout aussi simplement (figure 7-14) :

Private Sub Page_Load(...) Handles MyBase.Load lblNom.Text = Cache("Nom")End Sub

Figure 7.13 • Affichage d'une variable obtenue grâce au contexte

Chapitre 7 - Gestion de l’état, la session, les cookies

248

� Résumé du chapitreDans ce chapitre, nous avons vu que si la gestion de l'état est un véritable problème pour lesapplications Web, elle dispose également de nombreuses solutions. Plusieurs mécanismes per-mettent de stocker les données d'une page sur le client, ou sur le serveur. Des techniquesnouvelles dans ASP.NET permettent même de stocker les données sur un serveur partagé parplusieurs serveurs Web.

Figure 7.14 • Affichage de variables du cache

NoteLe cache dispose de fonctionnalités supplémentaires, comme la libération automatique des données quandelles ne sont pas utilisées