Vous êtes sur la page 1sur 29
Applications ASP.NET avec VB.NET © Groupe Eyrolles, 2003, ISBN : 2-212-11280-7 Gérard Frantz

Applications ASP.NET

avec VB.NET

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

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

Gérard Frantz

C

h

a

p

i

t

r

e

7

C h a p i t r e 7 Gestion de l'état, la session, les cookies

Gestion de l'état, la session, les cookies

DANS

CE

CHAPITRE

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 une autre étant un appel avec un hyperlien.

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

221

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

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

Comme cela a été indiqué dans les chapitres précédents, le Web est par essence un système sans état : l'utilisateur demande une page, celle-ci est renvoyée par le serveur, puis tout est oublié ! 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 ajoute tout un ensemble de traitements spécifiques sur cette mécanique relativement primitive, afin de vous 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 la valeur de données d'une page à une autre. Les quatre premières techniques se servent du client pour 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.

222

Applications ASP.NET avec VB.NET

Mise en évidence du problème

Prenons 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 de classe appelée Nom (il s'agit d'un membre de la classe associée à la page) :

' Variable contenant le nom Private Nom As String

Private Sub btnOK_Click(

' Stocke le nom dans une variable Nom = txtNom.Text End Sub

)

Handles btnOK.Click

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) :

Figure 7.1

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

La page PageEtat1 ne conserve pas la valeur de la donnée Private Sub btnAfficheNom_Click( ) Handles

Private Sub btnAfficheNom_Click(

)

Handles btnAfficheNom.Click

' Affiche le contenu de la variable

lblNom.Text = Nom End Sub

223

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

Note
Note

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

Le seul problème avec ce code est qu'il ne fonctionne pas comme on le souhaite : le texte n'est jamais affiché dans le label ! Si on exécute l'application pas à pas, on peut voir que la variable Nom 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 un nouvel 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 page par le serveur, grosso modo entre les événements Load et Unload de la page. Dès que la page est retournée à l'utilisateur, l'objet correspondant est détruit et des données disparaissent (figure 7-2).

Figure 7.2

À chaque nouvelle page correspond un nouvel objet

et des données disparaissent (figure 7-2). Figure 7.2 • À chaque nouvelle page correspond un nouvel
et des données disparaissent (figure 7-2). Figure 7.2 • À chaque nouvelle page correspond un nouvel
et des données disparaissent (figure 7-2). Figure 7.2 • À chaque nouvelle page correspond un nouvel

224

Applications ASP.NET avec VB.NET

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

Figure 7.3

Les données sont stockées dans une zone spécifique

• Les données sont stockées dans une zone spécifique ● Stockage des données sur le client
• Les données sont stockées dans une zone spécifique ● Stockage des données sur le client
• Les données sont stockées dans une zone spécifique ● Stockage des données sur le client

Stockage des données sur le client

Les techniques exposées dans cette section stockent les données sur le client. Si cela permet d'alléger la charge du serveur, les données sont transportées avec chaque demande du client vers le serveur, et à chaque réponse du serveur.

225

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

Les données d'état de la page

À chaque page est associé un état d'affichage (View State), qui stocke l'ensemble des données

de la page et de ses contrôles. Cet état d'affichage est implémenté dans un objet de classe StateBag (littéralement, sac d'état), qui enregistre les données sous la forme de paires de clés

et de valeurs, dans un dictionnaire.

Note
Note

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

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 <input

type=hidden>). Le contenu de ce champ correspond à l'ensemble des valeurs qui se trouvent

dans l'objet StateBag, codées de telle façon qu'elles soient transportables sur le protocole HTTP

et 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.

Attention
Attention

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

On peut accéder à l'objet StateBag associé à une page grâce à la propriété ViewState de l'objet Page. La clé associée à une donnée est automatiquement créée si celle-ci n'existe pas, ou elle est 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 dans une variable de la classe, mais dans l'objet StateBag de la page. Pour minimiser les modifica-

226

Applications ASP.NET avec VB.NET

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

Private Property Nom() As String Get

Nom = ViewState("Nom") End Get Set(ByVal Value As String) ViewState("Nom") = Value End Set End Property

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

Private Sub btnOK_Click(

' Stocke le nom dans une variable Nom = txtNom.Text End Sub

)

Handles btnOK.Click

Private Sub btnAfficheNom_Click(

)

Handles btnAfficheNom.Click

' Affiche le contenu de la variable

lblNom.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

bien quand on clique sur le bouton (figure 7-4). Figure 7.4 • La page PageEtat1 conserve

227

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

Note
Note

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

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 pour conserver les valeurs des propriétés des contrôles de la page. Il faut en fait distinguer deux faç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 de l'environnement de conception des pages de la fenêtre des propriétés, ou directement dans le code HTML. Toutes ces modifications sont stockées dans la page aspx, dans le code HTML, 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 la valeur 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és txtNom1 et txtNom2. Un bouton dont le texte est En jaune change la couleur de fond des deux contrôles, en modifiant la valeur de leur propriété BackColor :

Private Sub btnChange_Click(

txtNom1.BackColor = Color.Yellow txtNom2.BackColor = Color.Yellow End Sub

)

Handles btnChange.Click

Un second bouton, OK, ne fait rien de particulier, si ce n'est qu'à son activation, la page est soumise 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 devient bien jaune, car le code ci-dessus a modifié cette couleur. Quand on clique ensuite sur le bouton OK, la couleur reste jaune bien qu'aucun code spécifique n'ait été exécuté sur le serveur. Cela

228

Applications ASP.NET avec VB.NET

signifie que la valeur de la couleur de fond des deux contrôles a bien été placée dans le sac de proprié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 le bouton OK.

Si on donne à la propriété EnableViewState du second contrôle TextBox la valeur False, et qu'on clique 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 du contrôle n'a pas été transmis.

Figure 7.5

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

le contrôle dont la propriété EnableViewState est True Si maintenant on donne à la propriété EnableViewState

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

Note
Note

On 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 <input

name=" La valeur de cette balise correspond au contenu du sac d'état codé.

type="hidden"

Note
Note

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

229

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

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 le client. 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 la génération de la page contenant le formulaire, on peut donner une valeur au champ caché, par exemple 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 un contrôle serveur HTML. La page ChampCache comprend un bouton de commande et un champ caché 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, par exemple, à un identificateur :

Figure 7.6

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

La page ChampCache stocke une donnée dans un champ caché Private Sub Page_Load( If Not IsPostBack

Private Sub Page_Load(

If Not IsPostBack Then ' Premier chargement, stocke l'identificateur Caché.Value = 5 End If End Sub

)

Handles MyBase.Load

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

230

Private Sub btnVoir_Click( ' Relit l'indentificateur lblID.Text = Caché.Value End Sub

)

Handles btnVoir.Click

Applications ASP.NET avec VB.NET

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

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

Note
Note

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

Passage de données par l'URL

Une autre technique de passage des données d'une page à l'autre consiste à les placer dans l'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 des paramè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. Chaque paramètre est constitué d'un nom et d'une valeur, séparés par un signe =. Les paramètres sont sé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 ne peut notamment pas y avoir de caractères accentués ou d'espaces. On peut utiliser la méthode UrlEncode de l'objet HttpServerUtility retournée par la propriété Server de la page. Cette méthode prend en paramètre une chaîne de caractères et retourne la même chaîne, dans laquelle les 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 de l'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 passage du nom différente (figure 7-7).

231

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

Figure 7.7

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

d'autres pages et de leur passer des données Quand on clique sur le premier bouton, Affiche

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

Private Sub btnOKURL_Click(

)

Handles btnOKURL.Click

Response.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. Le ré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) :

232

Private Sub Page_Load(

)

Handles MyBase.Load

lblNom.Text = Request.QueryString("Nom")

End Sub

Figure 7.8

Affichage du nom après passage par l'URL

Applications ASP.NET avec VB.NET

passage par l'URL Applications ASP.NET avec VB.NET Note L'exemple se trouve dans les pages SaisieNom et
Note
Note

L'exemple se trouve dans les pages SaisieNom et AfficheNomURL du projet Etat du répertoire 07 des exemples.

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 demande du serveur, par l'intermédiaire de la propriété Cookies de l'objet HttpResponse retourné par la proprié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.

Note
Note

Un 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 est passif et ne correspond pas à du code. Les sites Web utilisent souvent des cookies pour mémoriser le fait que l'utilisateur est passé par une page, et pour éventuellement stocker des informations liées à cet utilisateur (par exemple ses goûts, déduits de son parcours dans le site). Cela permet d'ajuster le contenu des pages du site lors d'une visite ultérieure.

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 est remplacé, dans le cas contraire, il est créé :

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

233

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

Un cookie écrit de cette façon n'est pas permanent : il n'existe qu'en mémoire, donc pendant la duré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'expiration ou jusqu'à ce qu'il soit effacé.

Note
Note

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

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, la valeur 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. Il est donc préférable de ne placer que de petites quantités de données dans les cookies, afin de ne pas grossir la trame HTTP circulant sur le réseau, d'autant plus que la taille d'un cookie est elle-même limitée.

Note
Note

L'utilisation de cookies peut être désactivée sur le poste de l'utilisateur. Si le fonctionnement de votre application dépend de leur emploi, il faut soit disposer d'une méthode alternative, soit avertir l'utilisateur que 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'objet HttpBrowserCapabilities, retourné par la propriété Browser de Request : Request.Browser.Cookie est True si le navigateur autorise les cookies, False dans le cas contraire.

234

Applications ASP.NET avec VB.NET

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 temporaire appelé 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.Click

Response.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) :

Figure 7.9

Affichage du nom après passage par cookie

: Figure 7.9 • Affichage du nom après passage par cookie Private Sub Page_Load( ) Handles

Private Sub Page_Load(

)

Handles MyBase.Load

lblNom.Text = Request.Cookies("Nom").Value

End Sub

Note
Note

L'exemple se trouve dans les pages SaisieNom et AfficheNomCookie du projet Etat du répertoire 07 des exemples.

235

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

Stockage des données sur le serveur

Toutes 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 beaucoup d'utilisateurs accèdent à l'application.

L'utilisateur peut être lié au serveur sur lequel se trouvent les données, bien qu'ASP.NET propose 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 à une application. 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épertoires sur un serveur Web donné.

Pour créer une variable d'application, il suffit de la nommer et de lui donner une valeur, un peu comme 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 faire quelques remarques :

Une variable d'application est vue par tous les utilisateurs de l'application. Il ne faut donc pas 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.

236

Applications ASP.NET avec VB.NET

Les variables d'application sont stockées dans le serveur Web qui les crée. Dans le cas d'une ferme de serveurs (plusieurs serveurs qui jouent des rôles semblables), la demande d'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 autre serveur.

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

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

Il faut cependant bien initialiser les variables d'application quelque part. Cela peut être fait quand l'application démarre, en plaçant du code spécifique dans le fichier global.asax de l'application qui est ajouté à un projet Web par Visual Studio .NET lors de sa création. Ce fichier comprend des données et du code globaux à l'application. On peut notamment y ajouter des procé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 les programmes nécessaires. Pour gérer les variables application, on peut écrire du code dans les procédures suivantes :

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

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

Note
Note

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

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 sont appelées à la première création. Il est donc généralement préférable d'initialiser les données dans le constructeur Init.

237

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

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

Private Sub btnOKApplication_Click(

Application.Lock() Application("Nom") = txtNom.Text Application.UnLock() Response.Redirect("AfficheNomApplication.aspx") End Sub

)

Handles btnOKApplication.Click

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

Attention
Attention

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

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

Private Sub Page_Load(

)

Handles MyBase.Load

' Donnée initialiée par la page appelante lblNom.Text = Application("Nom")

' Données initialisées dans Global.asax lblInit.Text = Application("Init") lblOnStart.Text = Application("OnStart") End Sub

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

238

Public Class Global Inherits System.Web.HttpApplication

Figure 7.10

Affichage du nom après passage par une variable Application

Applications ASP.NET avec VB.NET

une variable Application Applications ASP.NET avec VB.NET Public Overrides Sub Init() Application("Init") =

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 Sub End Class

Les variables partagées

L'utilisation de l'objet Application pour conserver des données était courante dans les versions précédentes d'ASP. Elle présente cependant quelques inconvénients, particulièrement le fait que les 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é Global par 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 le serveur, ASP.NET peut, soit fabriquer un nouvel objet Global, soit utiliser un objet existant. On ne peut donc pas avoir de certitude sur l'objet Global employé par une page, et ses variables d'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 donc globale à l'application.

239

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

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

Public Class Global Inherits System.Web.HttpApplication

Public Shared Nom As String

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

Private Sub btnOKShared_Click(

SyncLock Me Global.Nom = txtNom.Text End SyncLock Response.Redirect("AfficheNomShared.aspx") End Sub

)

Handles btnOKShared.Click

Le problème de l'accès simultané à la donnée par plusieurs threads se pose à nouveau. Il est réglé ici en plaçant le code qui accède à la donnée dans une section de synchronisation, ce qui garantit 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écessaire de 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

donnée en lecture seule, figure 7-11) : Figure 7.11 • Affichage du nom après passage par

240

Private Sub Page_Load(

)

lblNom.Text = Global.Nom

End Sub

Handles MyBase.Load

Applications ASP.NET avec VB.NET

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 reconnue par un identificateur de session créé par ASP.NET. Il s'agit d'une chaîne de caractères de 120 bits (par exemple, 302dvbynpstxl3i0rugg1b45), dont l'unicité est garantie grâce à l'utilisation d'un algorithme spécifique. De plus, la structure de cette chaîne est non triviale, ce qui évite qu'elle soit manipulée à l'insu du système (par exemple, pour se faire passer pour quelqu'un d'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 du systè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 le navigateur de l'utilisateur.

Pour accéder aux informations d'une session, la classe Page expose une propriété, Session, qui retourne une référence à un objet HttpSessionState. Celui-ci dispose de propriétés et de mé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'exemple suivant).

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 balise comprend plusieurs attributs qui définissent les caractéristiques de la session (tableau 7-1).

241

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

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.

Note
Note

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

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 poste de l'utilisateur par l'intermédiaire d'un cookie. En revanche, si on donne à cookieless la valeur True, le SessionID est transmis dans l'URL, sous la forme d'un pseudo-répertoire dont le nom est la valeur de l'identificateur.

242

Attention
Attention

Applications ASP.NET avec VB.NET

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

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

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

InProc, les données de session sont stockées en mémoire sur le serveur. Cette valeur donne les meilleures performances (il s'agit d'ailleurs de la valeur par défaut), mais ne permet 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 de stateConnectionString. 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, indique que les données sont stockées sur le serveur local (l'adresse IP 127.0.0.1 identifie le serveur local).

SQLServer, les données de session sont stockées sur le serveur SQL Server identifié par la 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 plusieurs processus.

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ême application. L'utilisation de cette valeur permet de ne pas lier un utilisateur à un processus particulier. 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 ferme de serveurs), le serveur d'état peut être commun à l'ensemble des serveurs Web. De cette façon, les demandes d'un utilisateur ne sont pas liées à un serveur physique particulier et la répartition de charge entre les serveurs peut être pleinement exploitée.

243

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

La valeur SQLState de l'attribut mode permet d'aller encore plus loin, puisque les données des variables d'application sont placées sur un serveur SQL Server. De cette façon, même si un serveur 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 fermeture d'une session permet de libérer toutes les données qui lui sont associées. Si l'application gère des données sensibles, comme un compte en banque, il peut être préférable de diminuer cette valeur, afin de ne pas garder en mémoire des données concernant un utilisateur qui n'utilise plus 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 les nommant : 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"

Note
Note

Il 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.

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

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

244

Figure 7.12

Affichage de variables de session

Applications ASP.NET avec VB.NET

de variables de session Applications ASP.NET avec VB.NET La valorisation de la variable à la suite

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

Private Sub btnOKSession_Click(

Session("Nom") = txtNom.Text Response.Redirect("AfficheNomSession.aspx") End Sub

)

Handles btnOKSession.Click

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(

lblNom.Text = Session("Nom") lblSessionID.Text = Session.SessionID lblSession.Text = Session("Start") lblSession1.Text = Session("OnStart") End Sub

)

Handles MyBase.Load

245

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

Le contexte

La propriété Context d'une page retourne l'objet HttpContext associé à la page. Celui-ci fournit des informations sur la requête HTTP ayant provoqué son appel. Parmi les membres de la classe HttpContext, 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 que l'appel de la page se fasse à l'aide de la méthode Server.Transfer et non pas Response.Redirect.

Note
Note

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

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 la page SaisieNom :

Private Sub Page_Load(

lblNom.Text = CType(context.Handler, SaisieNom).Nom End Sub

)

Handles MyBase.Load

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

246

' Propriété Nom pour le contexte Public ReadOnly Property Nom() As String Get

Return txtNom.Text End Get End Property

Private Sub btnOKContext_Click(

' Utilise Server.Transfer au lieu de Response.Redirect Server.Transfer("AfficheNomContext.aspx") End Sub

)

Handles btnOKContext.Click

Figure 7.13

Affichage d'une variable obtenue grâce au contexte

Applications ASP.NET avec VB.NET

obtenue grâce au contexte Applications ASP.NET avec VB.NET Le cache Le cache d'ASP.NET est un lieu

Le cache

Le cache d'ASP.NET est un lieu de stockage de données qui peut être utilisé à la fois pour cacher des pages, c'est-à-dire les mémoriser afin d'éviter de les régénérer à chaque demande, et pour enregistrer 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 le cache dispose également de mécanismes complémentaires qui permettent de contrôler la durée de vie des données qu'il contient en libérant la mémoire quand elle n'est pas utilisée, ou de conditionner 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( Cache("Nom") = txtNom.Text

Response.Redirect("AfficheNomCache.aspx") End Sub

)

Handles btnOKCache.Click

On peut également utiliser les méthodes Insert et Add de l'objet Cache pour ajouter des données dans le cache. Ces méthodes peuvent recevoir des paramètres complémentaires permettant de dé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(

lblNom.Text = Cache("Nom") End Sub

)

Handles MyBase.Load

247

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

Figure 7.14

Affichage de variables du cache

les cookies Figure 7.14 • Affichage de variables du cache Note Le cache dispose de fonctionnalités
Note
Note

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

Résumé du chapitre

Dans ce chapitre, nous avons vu que si la gestion de l'état est un véritable problème pour les applications 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 techniques nouvelles dans ASP.NET permettent même de stocker les données sur un serveur partagé par plusieurs serveurs Web.

248