ASP Net Vol 1

download ASP Net Vol 1

of 192

Transcript of ASP Net Vol 1

Dveloppement WEB avec ASP.NET 1.1 - Volume 1 -

[email protected] avril 2004

Annexes

1/192

IntroductionCe document est un support de cours : ce n'est pas un cours complet. Des approfondissements ncessitent l'aide d'un enseignant et par ailleurs un certain nombre de thmes n'ont pas t abords. Son criture a t influence par le pass de l'auteur qui avait crit auparavant deux documents sur le dveloppement web, en Java tout d'abord puis en PHP. Ces deux documents ont une structure analogue permettant de comparer les deux technologies sur les mmes exemples. Il a t ici fait de mme pour le dveloppement en ASP.NET. Cela donne un document assez diffrent de ce qu'on trouve en librairie o quasiment tous les livres insistent sur le fait qu'ASP.NET permet de dvelopper une application web comme on dveloppe une application windows. L'interface qui est prsente dans le navigateur du client peut tre construite comme une interface windows : avec des IDE tels que Visual Studio.NET ou WebMatrix, l'interface utilisateur est construite avec des objets graphiques que l'on dpose dans la fentre de conception ces objets ont des proprits, mthodes et gnrent des vnements Ici, on dit le strict minimum sur ces concepts considrs comme les plus novateurs de ASP.NET... Ces concepts importants mais non fondamentaux sont prsents dans le volume 2 de ce cours. Dans ce volume 1, il a sembl plus important d'insister sur les fondements du dveloppement web qu'on retrouvera quelque soit la technologie utilise (Java, PHP, ASP.NET). Les extensions propritaires de ASP.NET qui permettent une meilleure productivit seront vues ultrieurement. Nous insistons beaucoup dans notre prsentation du dveloppement web sur l'architecture MVC (Modle, Vue, Contrleur) souvent prconise pour construire des applications web. Ce concept est indpendant de la technologie utilise. Il se trouve qu'il cadre mal avec celui de concevoir une application web comme une application windows prconis par la technologie ASP.NET. C'est l'autre raison qui a fait que ce concept tant vant dans la littrature ASP.NET a t relgu dans le volume 2. Parce que ce document est destin des tudiants, nous n'utilisons pour nos exemples que des outils librement disponibles sur internet. Le lecteur pourra ainsi se les procurer et tester les exemples sur sa machine personnelle. L'annexe "Les outils du web" donne des indications pour rcuprer et installer ces outils. Ce document comporte peut-tre encore des erreurs : toute suggestion constructive est la bienvenue l'adresse [email protected]. Serge Tah Avril 2004

Annexes

2/192

1 Les basesDans ce chapitre, nous prsentons les bases de la programmation Web. Il a pour but essentiel de faire dcouvrir les grands principes de la programmation Web qui sont indpendants de la technologie particulire utilise pour les mettre en oeuvre. Il prsente de nombreux exemples qu'il est conseill de tester afin de "s'imprgner" peu peu de la philosophie du dveloppement web. Les outils gratuits ncessaires leurs tests sont prsents en fin de document dans l'annexe intitule "Les outils du web".

1.1Les composantes d'une application WebMachine Serveur serveur web rseau 3 Scripts Serveur 4 Base de donnes Scripts Navigateur 7 Page WEB 1 Machine Cliente navigateur 6 5

2

rseau Utilisateur 4 Machine X Base de donnes

Numro1 2

Rle OS Serveur Serveur Web

Exemples courants Linux, Windows Apache (Linux, Windows) IIS (NT), PWS(Win9x), Cassini (Windows+plate-forme .NET)

3

Scripts excuts ct serveur. Ils peuvent l'tre par des modules du serveur PERL (Apache, IIS, PWS) ou par des programmes externes au serveur (CGI). VBSCRIPT (IIS,PWS) JAVASCRIPT (IIS,PWS) PHP (Apache, IIS, PWS) JAVA (Apache, IIS, PWS) C#, VB.NET (IIS) Base de donnes - Celle-ci peut tre sur la mme machine que le programme Oracle (Linux, Windows) qui l'exploite ou sur une autre via Internet. MySQL (Linux, Windows) Postgres (Linux, Windows) Access (Windows) SQL Server (Windows) OS Client Navigateur Web Linux, Windows Netscape, Internet Explorer, Mozilla, Opera

4

5 6

7

Scripts excuts ct client au sein du navigateur. Ces scripts n'ont aucun VBscript (IE) accs aux disques du poste client. Javascript (IE, Netscape) Perlscript (IE) 3/192

Les bases

Applets JAVA

1.1

Les changes de donnes dans une application web avec formulaireMachine Cliente1 serveur web 3 4 Scripts Navigateur

Machine ServeurScripts Serveur SB Base de donnes SA

2 navigateur

CA

CB Page WEB

SC

CD utilisateur

Machine X

Base de donnes

Numro1 2

Rle Le navigateur demande une URL pour la 1re fois (http://machine/url). Auncun paramtre n'est pass. Le serveur Web lui envoie la page Web de cette URL. Elle peut tre statique ou bien dynamiquement gnre par un script serveur (SA) qui a pu utiliser le contenu de bases de donnes (SB, SC). Ici, le script dtectera que l'URL a t demande sans passage de paramtres et gnrera la page WEB initiale. Le navigateur reoit la page et l'affiche (CA). Des scripts ct navigateur (CB) ont pu modifier la page initiale envoye par le serveur. Ensuite par des interactions entre l'utilisateur (CD) et les scripts (CB) la page Web va tre modifie. Les formulaires vont notamment tre remplis. L'utilisateur valide les donnes du formulaire qui doivent alors tre envoyes au serveur web. Le navigateur redemande l'URL initiale ou une autre selon les cas et transmet en mme temps au serveur les valeurs du formulaire. Il peut utiliser pour ce faire deux mthodes appeles GET et POST. A rception de la demande du client, le serveur dclenche le script (SA) associ l'URL demande, script qui va dtecter les paramtres et les traiter. Le serveur dlivre la page WEB construite par programme (SA, SB, SC). Cette tape est identique l'tape 2 prcdente. Les changes se font dsormais selon les tapes 2 et 3.

3

4

1.2 NotationsDans la suite, nous supposerons qu'un certain nombre d'outils ont t installs et adopterons les notations suivantes : notation

signification racine de l'arborescence du serveur apache racine des pages Web dlivres par Apache. C'est sous cette racine que doivent se trouver les pages Web. Ainsi l'URL http://localhost/page1.htm correspond au fichier \page1.htm. racine de l'arborescence li l'alias cgi-bin et o l'on peut placer des scripts CGI pour Apache. Ainsi 4/192

Les bases

l'URL http://localhost/cgi-bin/test1.pl correspond au fichier \test1.pl.

racine des pages Web dlivres par IIS, PWS ou Cassini. C'est sous cette racine que doivent se trouver les pages Web. Ainsi l'URL http://localhost/page1.htm correspond au fichier \page1.htm. racine de l'arborescence du langage Perl. L'excutable perl.exe se trouve en gnral dans \bin. racine de l'arborescence du langage PHP. L'excutable php.exe se trouve en gnral dans . racine de l'arborescence de java. Les excutables lis java se trouvent dans \bin. racine du serveur Tomcat. On trouve des exemples de servlets dans \webapps\examples\servlets et des exemples de pages JSP dans \webbapps\examples\jsp

On se reportera pour chacun de ces outils l'annexe qui donne une aide pour leur installation.

1.3 Pages Web statiques, Pages Web dynamiquesUne page statique est reprsente par un fichier HTML. Une page dynamique est, elle, gnre " la vole" par le serveur web. Nous vous proposons dans ce paragraphe divers tests avec diffrents serveurs web et diffrents langages de programmation afin de montrer l'universalit du concept web. Nous utiliserons deux serveurs web nots Apache et IIS. Si IIS est un produit commercial, il est cependant dclin en deux versions plus limites mais gratuites : PWS pour les machines Win9x Cassini pour les machines Windows 2000 et XP Le dossier est habituellement le dossier [lecteur:\inetpub\wwwroot] o [lecteur] est le disque (C, D, ...) o a t install IIS. Il en est de mme pour PWS. Pour Cassini, le dossier dpend de la faon dont le serveur a t lanc. Dans l'annexe, il est montr que le serveur Cassini peut tre lanc dans une fentre Dos (ou par un raccourci) de la faon suivante :dos>webserver /port:N /path:"P" /vpath:"/V"

L'application [WebServer] appele galement serveur web Cassini admet trois paramtres : /port : n de port du service web. Peut-tre quelconque. A par dfaut la valeur 80 /path : chemin physique d'un dossier du disque /vpath : dossier virtuel associ au dossier physique prcdent. On prtera attention au fait que la syntaxe n'est pas /path=chemin mais /vpath:chemin, contrairement ce que dit le panneau d'aide de Cassini.

Si Cassini est lanc de la faon suivante :dos>webserver /port:N /path:"P" /vpath:"/"

alors le dossier P est la racine de l'arborescence web du serveur Cassini. C'est donc ce dossier qui est dsign par . Ainsi dans l'exemple suivant :dos>webserver /path:"d:\data\devel\webmatrix" /vpath:"/"

le serveur Cassini travaillera sur le port 80 et la racine de son arborescence est le dossier [d:\data\devel\webmatrix]. Les pages Web tester devront se trouver sous cette racine. Dans la suite, chaque application web sera reprsente par un unique fichier qu'on pourra construire avec n'importe quel diteur de texte. Aucun IDE n'est requis.

1.3.1 Page statique HTML (HyperText Markup Language)Considrons le code HTML suivant : essai 1 : une page statique Une page statique...

Les bases

5/192

qui produit la page web suivante :

Les tests - lancer le serveur Apache - mettre le script essai1.html dans - visualiser lURL http://localhost/essai1.html avec un navigateur - arrter le serveur Apache - lancer le serveur IIS/PWS/Cassini - mettre le script essai1.html dans - visualiser lURL http://localhost/essai1.html avec un navigateur

1.3.2 Une page ASP (Active Server Pages)Le script essai2.asp : essai 1 : une page asp Une page asp gnre dynamiquement par le serveur PWS Il est
A chaque fois que vous rafrachissez la page, l'heure change.

produit la page web suivante :

Le test - lancer le serveur IIS/PWS - mettre le script essai2.asp dans - demander lURL http://localhost/essai2.asp avec un navigateur

1.3.3 Un script PERL (Practical Extracting and Reporting Language)Le script essai3.pl :#!d:\perl\bin\perl.exe ($secondes,$minutes,$heure)=localtime(time); print dir ... 29/05/2003 11:00 53 248 WebServer.exe ...

Lanons [WebServer.exe] sans paramtres :E:\Program Files\Microsoft ASP.NET Web Matrix\v0.6.812>webserver

Le panneau ci-dessus nous indique que l'application [WebServer/Cassini] admet trois paramtres : /port : n de port du service web. Peut-tre quelconque. A par dfaut la valeur 80 /path : chemin physique d'un dossier du disque /vpath : dossier virtuel associ au dossier physique prcdent. La syntaxe est /vpath:chemin et non /vpath=chemin comme indiqu dans la fentre Cassini ci-dessus.

Nous placerons nos exemples dans une arborescence de fichiers de racine P avec des dossiers chap1, chap2, ... pour les diffrents chapitres de ce document. Nous associerons ce dossier physique P, le chemin virtuel V. Aussi lancerons-nous Cassini avec la commande Dos suivante :dos> WebServer /port:80 /path:P /vpath:V

Par exemple, si on veut que la racine physique du serveur soit le dossier [D:\data\devel\aspnet\poly] et sa racine virtuelle [aspnet], la commande Dos de lancement du serveur web sera :dos> WebServer /port:80 /path:D:\data\devel\aspnet\poly /vpath:/aspnet

On pourra mettre cette commande dans un raccourci. Une fois lanc Cassini installe une icne dans la barre des tches. En doublecliquant dessus, on a accs un panneau Arrt/Marche du serveur :

Introduction au dveloppement asp.net

39/192

Le panneau rappelle les trois paramtres avec lesquels il a t lanc. Il offre deux boutons d'arrt/marche ainsi qu'un lien de test vers la racine de son arborescence web. Nous le suivons. Un navigateur est ouvert et l'URL [http://localhost/aspnet] demande. Nous obtenons le contenu du dossier indiqu dans le champ [Physical Path] ci-dessus :

Dans l'exemple, l'URL demande correspond un dossier et non un document web, aussi le serveur a-t-il affich le contenu de ce dossier et non un document web particulier. Si dans ce dossier, il existe un fichier appel [default.aspx], celui-ci sera visualis. Construisons par exemple, le fichier suivant et plaons-le dans la racine de l'arborescence web de Cassini (d:\data\devel\aspnet\poly ici) : Page d'entre Page d'index... dos>dir d:\data\devel\aspnet\poly\default.aspx 23/03/2004 18:21 107 default.aspx

Demandons maintenant l'URL [http://localhost/aspnet] avec un navigateur :

On voit qu'en ralit c'est l'URL [http://localhost/aspnet/default.aspx] qui a t affiche. Dans la suite du document, nous indiquerons comment Cassini doit tre configur par la notation Cassini(path,vpath) o [path] est le nom du dossier racine de l'arborescence web du serveur et [vpath] le chemin virtuel associ. On se rappellera qu'avec le serveur Cassini(path,vpath), l'url [http://localhost/vpath/XX] correspond au chemin physique [path\XX]. Nous placerons tous nos documents sous une racine physique que nous appellerons . Ainsi nous pourrons parler du fichier \chap2\here1.aspx. Pour chaque lecteur cette racine sera un dossier de sa machine personnelle. Ici les copies d'cran montreront que ce dossier est souvent [d:\data\devel\aspnet\poly]. Ce ne sera cependant pas toujours le cas, les tests ayant t faits sur des machines diffrentes.

2.3 Premiers exemplesNous allons prsenter des exemples simples de page web dynamique cre avec VB.NET. Le lecteur est invit les tester afin de vrifier que son environnement de dveloppement est correctement install. Nous allons dcouvrir qu'il y a plusieurs faons de construire une page ASP.NET. Nous en choisirons une pour la suite de nos dveloppements.

Introduction au dveloppement asp.net

40/192

2.3.1 Exemple de base - variante 1Outils ncessaires : un diteur de texte, le serveur Web Cassini Nous reprenons l'exemple du chapitre prcdent. Nous construisons le fichier [heure1.aspx] suivant : Demo asp.net Il est

Ce code est du code HTML avec une balise spciale . A l'intrieur de cette balise, on peut mettre du code VB.NET. Ici le codeDate.Now.ToString("T")

produit une chane de caractres C reprsentant l'heure du moment. La balise est alors remplace par cette chane de caractres C. Ainsi si C est la chane 18:11:01, la ligne HTML contenant le code VB.NET devient :Il est 18:11:01

Plaons le code prcdent dans le fichier [\chap2\heure1.aspx]. Lanons Cassini(,/aspnet) et demandons avec un navigateur l'URL [http://localhost/aspnet/chap2/heure1.aspx] :

Une fois obtenu ce rsultat, nous savons que l'environnement de dveloppement est correctement install. La page [heure1.aspx] a t compile puisqu'elle contient du code VB.NET. Sa compilation a produit un fichier dll qui a t stock dans un dossier systme puis excut par le serveur Cassini.

2.3.2 Exemple de base - variante 2Outils ncessaires : un diteur de texte, le serveur Web Cassini La document [heure1.aspx] mlange code HTML et code VB.NET. Dans un exemple aussi simple, cela ne pose pas problme. Si on est amen inclure davantage de code VB.NET, on souhaitera sparer davantage le code HTML du code VB. Cela peut se faire en regroupant le code VB l'intrieur d'une balise : ' calcul des donnes afficher par le code HTML ... .... ' affichage des valeurs calcules par la partie script

L'exemple [heure2.aspx] montre cette mthode : Dim maintenant as String=Date.Now.ToString("T") Demo asp.net Il est

Introduction au dveloppement asp.net

41/192

Nous plaons le document [heure2.aspx] dans l'arborescence [\chap2\heure2.aspx] Cassini(,/aspnet) et demandons le document avec un navigateur :

du

serveur

web

2.3.3 Exemple de base - variante 3Outils ncessaires : un diteur de texte, le serveur Web Cassini Nous poussons plus loin la dmarche de sparation du code VB et du code HTML en les mettant dans deux fichiers spars. Le code HTML sera dans le document [heure3.aspx] et le code VB dans [heure3.aspx.vb]. Le contenu de [heure3.aspx] sera le suivant : Demo asp.net Il est

Il y a deux diffrences fondamentales : la directive [Page] avec des attributs encore inconnus l'utilisation de la variable [maintenant] dans le code HTML alors qu'elle n'est initialise nulle part La directive [Page] sert ici indiquer que le code VB qui va initialiser la page est dans un autre fichier. C'est l'attribut [src] qui indique ce dernier. Nous allons dcouvrir que le code VB est celui d'une classe qui s'appelle [heure3]. De faon transparente pour le dveloppeur, un fichier .aspx est transform en classe drivant d'une classe de base appele [Page]. Ici, notre document HTML doit driver de la classe qui dfinit et calcule les donnes qu'il doit afficher. Ici c'est la classe [heure3] dfinie dans le fichier [heure3.aspx.vb]. Aussi doit-on indiquer ce lien parent-fils entre le document VB [heure3.aspx.vb] et le document HTML [heure3.aspx]. C'est l'attribut [inherits] qui prcise ce lien. Il doit indiquer le nom de la classe dfinie dans le fichier point par l'attribut [src]. tudions maintenant le code VB de la page [heure3.aspx.vb] :Public Class heure3 Inherits System.Web.UI.Page ' donnes de la page web afficher Protected maintenant As String Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'on calcule les donnes de la page web maintenant = Date.Now.ToString("T") End Sub End Class

On notera les points suivants : le code VB dfinit une classe [heure3] drive de la classe [System.Web.UI.Page]. C'est toujours le cas, une page web devant toujours driver de [System.Web.UI.Page]. la classe dclare un attribut protg (protected) [maintenant]. On sait qu'un attribut protg est accessible directement dans les classes drives. C'est ce qui permet au document HTML [heure3.aspx] d'avoir accs la valeur de la donne [maintenant] dans son code. l'initialisation de l'attribut [maintenant] se fait dans une procdure [Page_Load]. Nous verrons ultrieurement qu'un objet de type [Page] est averti par le serveur Web d'un certain nombre d'vnements. L'vnement [Load] se produit lorsque l'objet [Page] et ses composants ont t crs. Le gestionnaire de cet vnement est dsign par la directive [Handles MyBase.Load]Private Sub XX(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

le nom [XX] du gestionnaire de l'vnement peut tre quelconque. Sa signature doit elle tre celle indique ci-dessus. Nous n'expliquerons pas celle-ci pour l'instant. Introduction au dveloppement asp.net 42/192

on utilise souvent le gestionnaire de l'vnement [Page.Load] pour calculer les valeurs des donnes dynamiques que doit afficher la page web.

Les documents [heure3.spx] et [heure3.aspx.vb] sont placs dans [\chap2]. Puis avec un navigateur, on demande l'URL [http://localhost/aspnet/chap2/heure3.aspx] au serveur web(,/aspnet) :

2.3.4 Exemple de base - variante 4Outils ncessaires : un diteur de texte, le serveur Web Cassini Nous gardons le mme exemple que prcdemment mais regroupons de nouveau tout le code dans un unique fichier [heure4.aspx] : ' donnes de la page web afficher Private maintenant As String ' evt page_load Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'on calcule les donnes de la page web maintenant = Date.Now.ToString("T") End Sub Demo asp.net Il est

Nous retrouvons la squence de l'exemple 2 : .... code VB ... code HTML

Cette fois-ci, le code VB a t structur en procdures. On retrouve la procdure [Page_Load] de l'exemple prcdent. On veut montrer ici, qu'une page .aspx seule (non lie un code VB dans un fichier spar) est transforme de faon implicite en classe drive de [Page]. Aussi peut-on utiliser les attributs, mthodes et vnements de cette classe. C'est ce qui est fait ici o on utilise l'vnement [Load] de cette classe. La mthode de test est identique aux prcdentes :

2.3.5 Exemple de base - variante 5Outils ncessaires : un diteur de texte, le serveur Web Cassini Comme dans l'exemple 3, on spare code VB et code HTML dans deux fichiers spars. Le code VB est plac dans [heure5.aspx.vb] : Introduction au dveloppement asp.net 43/192

Public Class heure5 Inherits System.Web.UI.Page ' donnes de la page web afficher Protected maintenant As String Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'on calcule les donnes de la page web maintenant = Date.Now.ToString("T") End Sub End Class

Le code HTML est plac dans [heure5.aspx] : Demo asp.net Il est

Cette fois-ci, la directive [Page] n'indique plus le lien entre le code HTML et le code VB. Le serveur web n'a plus la possibilit de retrouver le code VB pour le compiler (absence de l'attribut src). C'est nous de faire cette compilation. Dans une fentre dos, nous compilons donc la classe VB [heure5.aspx.vb] :dos>dir 23/03/2004 24/03/2004 24/03/2004 24/03/2004 24/03/2004 24/03/2004 24/03/2004 18:34 09:47 10:16 10:16 14:31 14:45 14:56 133 232 183 332 440 332 148 heure1.aspx heure2.aspx heure3.aspx heure3.aspx.vb heure4.aspx heure5.aspx.vb heure5.aspx

dos>vbc /r:system.dll /r:system.web.dll /t:library /out:heure5.dll heure5.aspx.vb Compilateur Microsoft (R) Visual Basic .NET version 7.10.3052.4 dos>dir heure5.dll 24/03/2004 14:51

3 072 heure5.dll

Ci-dessus, l'excutable [vbc.exe] du compilateur tait dans le PATH de la machine Dos. S'il ne l'avait pas t, il aurait fallu donner le chemin complet de [vbc.exe] qui se trouve dans l'arborescence du dossier o a t install SDK.NET. Les classes drives de [Page] ncessitent des ressources prsentes dans les DLL [system.dll, system.web.dll], d'o la rfrence de celles-ci via l'option /r du compilateur. L'option /t :library est l pour indiquer qu'on veut produire une DLL. L'option /out indique le nom du fichier produire, ici [heure5.dll]. Ce fichier contient la classe [heure5] dont a besoin le document web [heure5.aspx]. Seulement, le serveur web cherche les DLL dont il a besoin dans des endroits bien prcis. L'un de ces endroits est le dossier [bin] situ la racine de son arborescence. Cette racine est ce que nous avons appel . Pour le serveur IIS, c'est gnralement :\inetpub\wwwroot o est le lecteur (C, D, ...) o a t install IIS. Pour le serveur Cassini, cette racine correspond au paramtre /path avec lequel vous l'avez lanc. Rappelons que cette valeur peut tre obtenue en double-cliquant sur l'icne du serveur dans la barre des tches :

correspond l'attribut [Physical Path] ci-dessus. Nous crons donc un dossier \bin et plaons [heure5.dll] dedans :

Introduction au dveloppement asp.net

44/192

Nous sommes prts. Nous Cassini(,/aspnet) :

demandons

l'URL

[http://localhost/aspnet/chap2/heure5.aspx]

au

serveur

2.3.6 Exemple de base - variante 6Outils ncessaires : un diteur de texte, le serveur Web Cassini Nous avons montr jusqu'ici qu'une application web dynamique avait deux composantes : 1. du code VB pour calculer les parties dynamiques de la page 2. du code HTML incluant parfois du code VB, pour l'affichage de ces valeurs dans la page. Cette partie reprsente la rponse qui est envoye au client web. La composante 1 est appele la composante contrleur de la page et la partie 2 la composante prsentation. La partie prsentation doit contenir le moins de code VB possible, voire pas de code VB du tout. On verra que c'est possible. Ici, nous montrons un exemple o il n'y a qu'un contrleur et pas de composante prsentation. C'est le contrleur qui gnre lui-mme la rponse au client sans l'aide de la composante prsentation. Le code de prsentation devient le suivant :

On voit qu'il n'y a plus aucun code HTML dedans. La rponse est labore directement dans le contrleur :Public Class heure6 Inherits System.Web.UI.Page Private Sub Page_Load(ByVal sender As System.Object, ByVal MyBase.Load ' on labore la rponse Dim HTML As String HTML = "heure6Il est " HTML += Date.Now.ToString("T") HTML += "" ' on l'envoie Response.Write(HTML) End Sub End Class e As System.EventArgs) Handles

Le contrleur labore ici la totalit de la rponse plutt que les seules parties dynamiques de celle-ci. De plus il l'envoie. Il le fait avec la proprit [Response] de type [HttpResponse] de la classe [Page]. C'est un objet qui reprsente la rponse faite par le serveur au client. La classe [HttpResponse] dispose d'une mthode [Write] pour crire dans le flux HTML qui sera envoy au client. Ici, nous mettons la totalit du flux HTML envoyer dans la variable [HTML] et nous envoyons celle-ci au client par [Response.Write(HTML)]. Nous demandons l'url [http://localhost/aspnet/chap2/heure6.aspx] au serveur Cassini (,/aspnet) :

Introduction au dveloppement asp.net

45/192

2.3.7 ConclusionPar la suite, nous utiliserons la mthode 3 qui place le code VB et le code HTML d'un document Web dynamique dans deux fichiers spars. Cette mthode a l'avantage de dcouper une page web en deux composantes : 1. 2. une composante contrleur compose uniquement de code VB pour calculer les parties dynamiques de la page une composante prsentation qui est la rponse envoye au client. Elle est compose de code HTML incluant parfois du code VB pour l'affichage des valeurs dynamiques. Nous viserons toujours avoir le minimum de code VB dans la partie prsentation, l'idal tant de ne pas en avoir du tout.

Comme l'a montr la mthode 5, le contrleur pourra tre compil indpendamment de l'application web. Cela prsente l'avantage de se concentrer uniquement sur le code et d'avoir chaque compilation la liste de toutes les erreurs. Une fois le contrleur compil, l'application web peut tre teste. Sans compilation pralable, c'est le serveur web qui fera celle-ci, et alors les erreurs seront signales une par une. Cela peut tre jug fastidieux. Pour les exemples qui vont suivre, les outils suivants suffisent : un diteur de texte pour construire les documents HTML et VB de l'application lorsqu'ils sont simples un IDE de dveloppement .NET pour construire les classes VB.NET afin de bnficier de l'aide apporte par ce type d'outil l'criture de code. Un tel outil est par exemple CSharpDevelop (http://www.icsharpcode.net). Un exemple d'utilisation est montr dans l'annexe [Les outils du dveloppement web]. l'outil WebMatrix pour construire les pages de prsentation de l'application (cf l'annexe [Les outils du dveloppement web]). le serveur Cassini Tous ces outils sont gratuits.

Introduction au dveloppement asp.net

46/192

3 Les fondamentaux du dveloppement ASP.NET3.1 La notion d'application web ASP.NET3.1.1 IntroductionUne application web est une application regroupant divers documents (HTML, code .NET, images, sons, ...). Ces documents doivent tre sous une mme racine qu'on appelle la racine de l'application web. A cette racine est associ un chemin virtuel du serveur web. Nous avons rencontr la notion de dossier virtuel pour le serveur web Cassini. Cette notion existe galement pour le serveur web IIS. Une diffrence importante entre les deux serveurs est qu' un moment donn, IIS peut avoir un nombre quelconque de dossiers virtuels alors que le serveur web Cassini n'en a qu'un, celui qui a t spcifi son lancement. Cela signifie que le serveur IIS peut servir plusieurs applications web simultanment alors que le serveur Cassini n'en sert qu'une la fois. Dans les exemples prcdents, le serveur Cassini tait toujours lanc avec les paramtres (,/aspnet) qui associaient le dossier virtuel /aspnet au dossier physique . Le serveur web servait donc toujours la mme application web. Cela ne nous a pas empchs d'crire et de tester des pages diffrentes et indpendantes l'intrieur de cette unique application web. Chaque application web a des ressources qui lui sont propres et qui se trouvent sous sa racine physique : un dossier [bin] dans lequel on peut placer des classes pr-compiles un fichier [global.asax] qui permet de d'initialiser l'application web dans son ensemble ainsi que l'environnement d'excution de chacun de ses utilisateurs un fichier [web.config] qui permet de paramtrer le fonctionnement de l'application un fichier [default.aspx] qui joue le rle de porte d'entre de l'application ... Ds qu'une application utilise l'une de ces trois ressources, elle a besoin d'un chemin physique et virtuel qui lui soient propres. Il n'y a en effet aucune raison pour que deux applications web diffrentes soient configures de la mme faon. Nos exemples prcdents ont pu tous tre placs dans la mme application (,/aspnet) parce qu'ils n'utilisaient aucune des ressources prcdentes. Revenons sur l'architecture MVC prconise dans le chapitre prcdent, pour le dveloppement d'une application web : Client Interface client Logique applicative Contrleur CONTRLEUR Classes mtier Classes d'accs donnes Donnes Sources de donnes

MODELE VUES page1 pagen

L'application web est forme des fichiers de classe (contrleur, classes mtier, classes d'accs aux donnes) et des fichiers de prsentation (documents HTML, images, sons, feuilles de style,..). L'ensemble de ces fichiers sera plac sous une mme racine que nous appellerons parfois . Cette racine sera associe un chemin virtuel . L'association entre ce chemin virtuel et chemin physique se fait par configuration du serveur web. On a vu que pour le serveur Cassini, cette association se faisait au lancement du serveur. Par exemple dans une fentre dos, on lancerait Cassini par :webserver.exe /port:80 /path: /vpath:

Dans le dossier , on trouvera selon nos besoins : le dossier [bin] pour y placer des classes pr-compiles (dll) le fichier [global.asax] lorsque nous aurons besoin de faire des initialisation soit lors de l'initialisation de l'application, soit lors de celle d'une session utilisateur le fichier [web.config] lorsque nous aurons besoin de paramtrer l'application le fichier [default.aspx] lorsque nous aurons besoin d'une page par dfaut dans l'application

Les fondamentaux du dveloppement asp.net

47/192

Afin de respecter ce concept d'application web, les exemples venir seront tous placs dans un dossier propre l'application auquel sera associ un dossier virtuel , le serveur Cassini tant lanc de faon lier ces deux paramtres.

3.1.2 Configurer une application webSi est la racine d'une application ASP.NET, on peut utiliser le fichier \web.config pour configurer celle-ci. Ce fichier est au format XML. Voici un exemple :

On prtera attention au fait que les balises XML sont sensibles la casse. Toutes les informations de configuration doivent tre entre les balises et . Il existe de nombreuses sections de configuration utilisables. Nous n'en prsentons qu'une ici, la section qui permet d'initialiser des donnes avec la balise . La syntaxe de cette balise est la suivante :

Lorsque le serveur Web lance une application, il regarde si dans il y a un fichier appel [web.config]. Si oui, il le lit et mmorise ses informations dans un objet de type [ConfigurationSettings] qui sera disponible toutes les pages de l'application tant que celle-ci est active. La classe [ConfigurationSettings] a une mthode statique [AppSettings] :

Pour obtenir la valeur d'une cl C du fichier de configuration, on crit [ConfigurationSettings.AppSettings("C")]. On obtient une chane de caractres. Pour exploiter le fichier de configuration prcdent, crons une page [default.aspx]. Le code VB du fichier [default.aspx.vb] sera le suivant :Imports System.Configuration Public Class _default Inherits System.Web.UI.Page Protected nom As String Protected age As String Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'on rcupre les informations de configuration nom = ConfigurationSettings.AppSettings("nom") age = ConfigurationSettings.AppSettings("age") End Sub End Class

On voit qu'au chargement de la page, les valeurs des paramtres de configuration [nom] et [age] sont rcupres. Elles vont tre affiches par le code de prsentation de [default.aspx] : Configuration Nom :
Age :

Les fondamentaux du dveloppement asp.net

48/192

Pour le test, on met les fichiers [web.config], [default.aspx] et [default.aspx.vb] dans le mme dossier :D:\data\devel\aspnet\poly\chap2\config1>dir 30/03/2004 15:06 418 default.aspx.vb 30/03/2004 14:57 236 default.aspx 30/03/2004 14:53 186 web.config

Soit le dossier o se trouvent les trois fichiers de l'application. Le serveur Cassini est lanc avec les paramtres (,/aspnet/config1). Nous demandons l'URL [http://localhost/aspnet/config1]. Comme [config1] est un dossier, le serveur web va chercher un fichier [default.aspx] dedans et l'afficher s'il le trouve. Ici, il va le trouver :

3.1.3 Application, Session, Contexte

3.1.3.1 Le fichier global.asaxLe code du fichier [global.asax] est toujours excut avant que la page demande par la requte courante ne soit charge. Il doit tre situ dans la racine de l'application. S'il existe, le fichier [global.asax] est utilis divers moments par le serveur web : 1. lorsque l'application web dmarre ou se termine 2. lorsqu'une session utilisateur dmarre ou se termine 3. lorsqu'une requte utilisateur dmarre Comme pour les pages .aspx, le fichier [global.asax] peut tre crit de diffrentes faons et en particulier en sparant code VB dans une classe contrleur et code de prsentation. C'est le choix fait par dfaut par l'outil Visual Studio et nous allons faire ici de mme. Il n'y a normalement aucune prsentation faire, ce rle tant dvolu aux pages .aspx. Le contenu du fichier [global.asax] est alors rduit une directive rfrenant le fichier contenant le code du contrleur :

On remarquera que la directive n'est plus [Page] mais [Application]. Le code du contrleur [global.asax.vb] associ et gnr par l'outil Visual studio est le suivant :Imports System Imports System.Web Imports System.Web.SessionState Public Class Global Inherits System.Web.HttpApplication Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs) ' Se dclenche lorsque l'application est dmarre End Sub Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs) ' Se dclenche lorsque la session est dmarre End Sub Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs) ' Se dclenche au dbut de chaque demande End Sub Sub Application_AuthenticateRequest(ByVal sender As Object, ByVal e As EventArgs) ' Se dclenche lors d'une tentative d'authentification de l'utilisation End Sub Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs) ' Se dclenche lorsqu'une erreur se produit End Sub Sub Session_End(ByVal sender As Object, ByVal e As EventArgs) ' Se dclenche lorsque la session se termine End Sub Sub Application_End(ByVal sender As Object, ByVal e As EventArgs) ' Se dclenche lorsque l'application se termine

Les fondamentaux du dveloppement asp.net

49/192

End Sub End Class

On notera que la classe du contrleur drive de la classe [HttpApplication]. Dans la vie d'une application, il existe plusieurs vnements importants. Ceux-ci sont grs par des procdures dont le squelette est donn ci-dessus. [Application_Start] : rappelons qu'une application web est "enferme" dans un chemin virtuel. L'application dmarre ds qu'une page situe dans ce chemin virtuel est demande par un client. La procdure [Application_Start] est alors excute. Ce sera l'unique fois. On fera dans cette procdure, toute initialisation utile l'application, comme par exemple crer des objets dont la dure de vie est celle de l'application. [Application-End] : est excute quand l'application est termine. A toute application est associ un dlai d'inactivit, configurable dans [web.config], au bout duquel l'application est considre comme termine. C'est donc le serveur web qui prend cette dcision en fonction du paramtrage de l'application. Le dlai d'inactivit d'une application est dfini comme le temps pendant lequel aucun client n'a fait une demande pour une ressource de l'application. [Session-Start]/[Session_End] : A tout client est attache une session sauf si l'application est configure comme n'ayant pas de session. Un client n'est pas un utilisateur devant son cran. Si celui-ci a ouvert 2 navigateurs pour interroger l'application, il reprsente deux clients. Un client est caractris par un jeton de session qu'il doit joindre chacune de ses demandes. Ce jeton de session est une suite de caractres gnre alatoirement par le serveur web et unique. Deux clients ne peuvent avoir le mme jeton de session. Ce jeton va suivre le client de la faon suivante : o le client qui fait sa premire demande n'envoie pas de jeton de session. Le serveur web reconnat ce fait et lui en attribue un. C'est le dbut de la session et la procdure [Session_Start] est excute. Ce sera l'unique fois. o le client fait ses demandes suivantes en envoyant le jeton qui l'identifie. Cela va permettre au serveur web de retrouver des informations lies ce jeton. Cela va permettre un suivi entre les diffrentes demandes du client. o l'application peut mettre la disposition d'un client, un formulaire de fin de session. Dans ce cas, c'est le client qui demande lui-mme la fin de sa session. La procdure [Session_End] sera excute. Ce sera l'unique fois. o le client peut ne jamais demander lui-mme la fin de sa session. Dans ce cas, aprs un certain dlai d'inactivit de la session, lui-aussi configurable par [web.config], la session sera termine par le serveur web. La procdure [Session_End] sera alors excute. [Application_BeginRequest] : cette procdure est excute ds qu'une nouvelle demande arrive. Elle est donc excute chaque requte d'un client quelconque. C'est un bon endroit pour examiner la requte avant de la transmettre la page qui a t demande. On peut mme prendre la dcision de la rorienter vers une autre page. [Application_Error] : est excute chaque fois que se produit une erreur non gre explicitement par le code du contrleur [global.asax.vb]. On peut ici, rorienter la demande du client vers une page expliquant la cause de l'erreur.

Si aucun de ces vnements ne doit tre gr, alors le fichier [global.asax] peut tre ignor. C'est ce qui a t fait avec les premiers exemples de ce chapitre.

3.1.3.2 Exemple 1Dveloppons une application pour mieux apprhender les trois moments que sont : le dmarrage de l'application, de la session, d'une demande client. Le fichier [global.asax] sera le suivant :

Le fichier [global.asax.vb] associ sera le suivant :Imports System Imports System.Web Imports System.Web.SessionState Public Class global Inherits System.Web.HttpApplication Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs) ' Se dclenche lorsque l'application est dmarre ' on note l'heure Dim startApplication As String = Date.Now.ToString("T") ' on la range dans le contexte de l'application Application.Item("startApplication") = startApplication End Sub Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs) ' Se dclenche lorsque la session est dmarre ' on note l'heure Dim startSession As String = Date.Now.ToString("T") ' on la met dans la session Session.Item("startSession") = startSession End Sub

Les fondamentaux du dveloppement asp.net

50/192

Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs) ' on note l'heure Dim startRequest As String = Date.Now.ToString("T") ' on la met dans la session Context.Items("startRequest") = startRequest End Sub End Class

Les points importants du code sont les suivants : le serveur web rend disponible la classe [HttpApplication] de [global.asax.vb] un certain nombre d'objets : o Application de type [HttpApplicationState] - reprsente l'application web - donne accs un dictionnaire d'objets [Application.Item] accessible tous les clients de l'application - permet le partage d'informations entre diffrents clients - l'accs simultan de plusieurs clients une mme donne en lecture/criture ncessite une synchronisation des clients. o Session de type [HttpSessionState] - reprsente un client particulier - donne accs un dictionnaire d'objets [Session.Item] accessible toutes les requtes de ce client - va permettre de mmoriser des informations sur un client qu'on va pouvoir retrouver au fil des requtes de celui-ci. o Request de type [HttpRequest] - reprsente la requte HTTP courante du client o Response de type [HttpResponse] - reprsente la rponse HTTP en cours de construction du serveur au client o Server de type [HttpServerUtility] - offre des mthodes utilitaires notamment pour transfrer la requte une autre page que celle prvue initialement. o Context de type [HttpContext] - cet objet est recr chaque nouvelle requte mais est partag par toutes les pages qui participent au traitement de la requte - permet de transmettre des informations de page en page lors du traitement d'une requte grce son dictionnaire Items. la procdure [Application_Start] note le dbut de l'application dans une variable stocke dans un dictionnaire accessible au niveau application la procdure [Session_Start] note le dbut de la session dans une variable stocke dans un dictionnaire accessible au niveau session la procdure [Application_BeginRequest] note le dbut de la requte dans une variable stocke dans un dictionnaire accessible au niveau requte (c.a.d disponible pendant tout le temps de son traitement mais perdue la fin de celui-ci) La page cible sera la page [main.aspx] suivante : global.asax jeton de session :
dbut Application :
dbut Session :
dbut Requte :

Cette page de prsentation affiche des valeurs calcules par son contrleur [main.aspx.vb] :Public Class main Inherits System.Web.UI.Page Protected Protected Protected Protected startApplication As String startSession As String startRequest As String jeton as String e As System.EventArgs) Handles

Private Sub Page_Load(ByVal sender As System.Object, ByVal MyBase.Load ' on rcupre les infos de l'application et de la session jeton=Session.SessionId startApplication = Application.Item("startApplication").ToString startSession = Session.Item("startSession").ToString startRequest = Context.Items("startRequest").ToString End Sub End Class

Le contrleur se contente de rcuprer les trois informations places respectivement dans l'application, la session, le contexte par [global.asax.vb]. Les fondamentaux du dveloppement asp.net 51/192

Nous testons l'application de la faon suivante : 1. les fichiers sont rassembls dans un mme dossier

2. 3.

le serveur Cassini est lanc avec les paramtres (,/aspnet/globalasax1) un premier client demande l'url [http://localhost/aspnet/globalasax1/main.aspx] et obtient le rsultat suivant :

4.

le mme client fait une nouvelle requte (option Reload du navigateur) :

On peut constater que seule l'heure de la requte a chang. Ceci montre deux choses : les procdures [Application_Start] et [Session_Start] de [global.asax] n'ont pas t excutes lors de la seconde requte. les objets [Application] et [Session] o taient stockes les heures de dbut de l'application et de la session sont encore disponibles pour la seconde requte. 5. on lance un second navigateur pour crer un second client et nous redemandons la mme url :

Cette fois-ci, nous voyons que l'heure de la session a chang. Le deuxime navigateur, bien que sur la mme machine, a t considr comme un second client et une nouvelle session a t cre pour lui. On peut constater que les deux clients n'ont pas le mme jeton de session. L'heure de dbut de l'application n'a pas chang, ce qui signifie que : la procdure [Application_Start] de [global.asax.vb] n'a pas t excute l'objet [Application] o a t stocke l'heure de dbut de l'application est accessible au second client. C'est donc dans cet objet qu'il faut stocker les informations que doivent se partager les diffrents clients de l'application, l'objet [Session] lui, servant stocker des informations que doivent se partager les requtes d'un mme client.

Les fondamentaux du dveloppement asp.net

52/192

3.1.3.3 Une vue d'ensembleAvec ce que nous avons appris jusqu' maintenant, nous sommes en mesure de faire un premier schma explicatif du fonctionnement d'un serveur web et des application web qu'il sert : APPLICATION A client-1A client-2A Serveur WEB ApplicationA Session-1A donnes global.asax page-1A.aspx page-2A.aspx code Session-2A .aspx

APPLICATION B client-1B client-2B ApplicationB Session-1B donnes Session-2B global.asax page-1B.aspx page-2B.aspx code .aspx

Le schma prcdent nous montre un serveur servant deux applications notes A et B, chacune avec deux clients. Un serveur web est capable de servir plusieurs applications web simultanment. Celles-ci sont totalement indpendantes les unes des autres. Nous raisonnerons sur l'application A. Le traitement d'une requte du client-1A l'application A va se drouler de la faon suivante : le client 1A demande au serveur web une ressource qui appartient au domaine de l'application A. Cela veut dire qu'il demande une URL de la forme [http://machine:port/VA/ressource] o VA est le chemin virtuel de l'application A. si le serveur web dtecte que c'est la 1re demande d'une ressource de l'application A, il dclenche l'vnement [Application_Start] du fichier [global.asax] de l'application A. Un objet [ApplicationA] de type [HttpApplicationState] va tre construit. Les diffrents codes de l'application stockeront dans cet objet des donnes de porte [Application], c.a.d. des donnes concernant tous les utilisateurs. L'objet [ApplicationA] va exister jusqu' ce que le serveur web dcharge l'application A. si le serveur web dtecte de plus qu'il a affaire un nouveau client de l'application A, il va dclencher l'vnement [Session_Start] du fichier [global.asax] de l'application A. Un objet [Session-1A] de type [HttpSessionState] va tre construit. Cet objet va permettre l'application A de stocker des objets de porte [Session], c.a.d. des objets appartenant un client prcis. L'objet [Session-1A] va exister tant que le client 1A fera des requtes. Il va permettre un suivi de ce client. Le serveur web dtecte qu'il a affaire un nouveau client dans deux cas : o le client ne lui a pas envoy de jeton de session dans les enttes HTTP de sa requte o le client lui a envoy un jeton de session qui n'existe pas (mauvais fonctionnement du client ou tentative de piratage) ou qui n'existe plus. Un jeton de session expire en effet au bout d'un certain dlai d'inactivit du client (20 mn par dfaut avec IIS). Ce dlai est programmable. dans tous les cas, le serveur web va dclencher l'vnement [Application_BeginRequest] du fichier [global.asax]. Cet vnement dmarre le traitement d'une requte client. Il est frquent de ne pas traiter cet vnement et de passer la main la page demande par le client qui elle traitera la requte. On peut aussi utiliser cet vnement pour analyser la requte, la traiter et dcider de la page qui doit tre envoye en rponse. Nous utiliserons cette technique pour mettre en place une application respectant l'architecture MVC dont nous avons parl. une fois le filtre de [global.asax] pass, la requte du client est passe une page .aspx qui va traiter la requte. Nous verrons ultrieurement qu'il est possible de passer la requte au travers d'un filtre de plusieurs pages. La dernire sera charge d'envoyer la rponse au client. Les pages peuvent ajouter la requte initiale du client, des informations qu'elles ont calcules. Elles peuvent stocker ces informations dans la collection Context.Items. En effet, toutes les pages engages dans le traitement de la requte d'un client ont accs ce rservoir de donnes. le code des diffrentes pages a accs aux rservoirs de donnes que sont les objets [ApplicationA], [Session-1A], ... Il faut se souvenir que le serveur web traite simultanment plusieurs clients pour l'application A. Tous ces clients ont accs l'objet [Application A]. S'ils doivent modifier des donnes dans cet objet, il y a un travail de synchronisation des clients 53/192

Les fondamentaux du dveloppement asp.net

faire. Chaque client XA a de plus accs au rservoir de donnes [Session-XA]. Celui-ci lui tant rserv, il n'y a pas l de synchronisation faire. le serveur web sert plusieurs applications web simultanment. Il n'y a aucune interfrence entre les clients de ces diffrentes applications.

De ces explications, on retiendra les points suivants : un moment donn, un serveur web sert de multiples clients de faon simultane. Cela signifie qu'il n'attend pas la fin d'une requte pour en traiter une autre. A un temps T, il y a donc plusieurs requtes en cours de traitement appartenant des clients diffrents pour des applications diffrentes. On appelle parfois threads d'excution, les codes de traitement qui se droulent en mme temps au sein du serveur web. les threads d'excution des clients d'applications web diffrentes n'interfrent pas entre-eux. Il y a tanchit. les threads d'excution des clients d'une mme application peuvent avoir partager des donnes : o les threads d'excution des requtes de deux clients diffrents (pas le mme jeton de session) peuvent partager des donnes au moyen de l'objet [Application]. o les threads d'excution des requtes successives d'un mme client peuvent partager des donnes au moyen de l'objet [Session]. o les threads d'excution des pages successives traitant une mme requte d'un client donn peuvent partager des donnes au moyen de l'objet [Context].

3.1.3.4 Exemple 2Dveloppons un nouvel exemple mettant en lumire ce qui vient d'tre vu. Nous rassemblons dans le mme dossier les fichiers suivants : [global.asax]

[global.asax.vb]Imports System Imports System.Web Imports System.Web.SessionState Public Class global Inherits System.Web.HttpApplication Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs) ' Se dclenche lorsque l'application est dmarre ' init compteur de clients Application.Item("nbRequtes") = 0 End Sub Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs) ' Se dclenche lorsque la session est dmarre ' init compteur de requtes Session.Item("nbRequtes") = 0 End Sub End Class

Le principe de l'application va tre de compter le nombre total de requtes faites l'application et le nombre de requtes par client. Lorsque l'application dmarre [Application_Start], on met 0 le compteur des requtes faites l'application. Ce compteur est plac dans la porte [Application] car il doit tre incrment par tous les clients. Lorsqu'un client se prsente pour la premire fois [Session_Start], on met 0 le compteur des requtes faites par ce client. Ce compteur est plac dans la porte [Session] car il ne concerne qu'un client donn. Une fois [global.asax] excut, le fichier [main.aspx] suivant sera excut : application-session jeton de session :
requtes Application :
requtes Client :

Les fondamentaux du dveloppement asp.net

54/192


Il affiche trois informations calcules par son contrleur : 1. l'identit du client via son jeton de session : [jeton] 2. le nombre total de requtes faites l'application : [nbRequtesApplication] 3. le nombre total de requtes faites par le client identifi en 1 : [nbRequtesClient] Les trois informations sont calcules dans [main.aspx.vb] :Public Class main Inherits System.Web.UI.Page Protected nbRequtesApplication As String Protected nbRequtesClient As String Protected jeton As String Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load ' une requte de plus pour l'application Application.Item("nbRequtes") = CType(Application.Item("nbRequtes"), Integer) + 1 ' une requte de plus dans la session Session.Item("nbRequtes") = CType(Session.Item("nbRequtes"), Integer) + 1 ' init variables de prsentation nbRequtesApplication = Application.Item("nbRequtes").ToString jeton = Session.SessionID nbRequtesClient = Session.Item("nbRequtes").ToString End Sub End Class

Lorsque [main.aspx.vb] est excute, nous sommes en cours de traitement d'une requte d'un client donn. Nous utilisons l'objet [Application] pour incrmenter le nombre de requtes de l'application et l'objet [Session] pour incrmenter le nombre de requtes du client dont on est en train de traiter la requte. Rappelons que si tous les clients d'une mme application partagent le mme objet [Application], ils ont chacun un objet [Session] qui leur est propre. Nous testons l'application en plaant les quatre fichiers prcdents dans un dossier que nous appelons et nous lanons le serveur Cassini avec les paramtres (,/aspnet/webapplia). Nous lanons un premier navigateur et demandons l'url [http://localhost/aspnet/webapplia/main.aspx] :

Nous faisons une seconde requte avec le bouton [Reload] :

Nous lanons un second navigateur pour demander la mme url. Pour le serveur web, c'est un nouveau client :

On peut constater que le jeton de session a chang et qu'on a donc un nouveau client. Cela est reflt dans le nombre de requtes du client. Revenons maintenant au 1er navigateur et redemandons encore la mme url :

Les fondamentaux du dveloppement asp.net

55/192

Le nombre de requtes faites l'application sont bien toutes comptes.

3.1.3.5 De la ncessit de synchroniser les clients d'une applicationDans l'application prcdente, le compteur de requtes faites l'application est incrment dans la procdure [Form_Load] de la page [main.aspx] de la faon suivante :' une requte de plus pour l'application Application.Item("nbRequtes") = CType(Application.Item("nbRequtes"), Integer) + 1

Cette instruction, quoique simple, ncessite plusieurs instructions du processeur pour tre excute. Supposons qu'il en faille trois : 1. lecture du compteur 2. incrmentation du compteur 3. rcriture du compteur Le serveur web s'excute sur une machine multi-tches, ce qui entrane que chaque tche se voit accord le processeur pendant quelques millisecondes avant de le perdre puis de le retrouver aprs que toutes les autres tches aient eu elles aussi leur quantum de temps. Supposons que deux clients A et B fassent une requte en mme temps au serveur web. Admettons que le client A passe le premier, qu'il arrive dans la procdure [Form_Load] de [main.aspx.vb], lise le compteur (=100) puis est interrompu parce que son quantum de temps est puis. Supposons maintenant que ce soit le tour du client B et que celui-ci subisse le mme sort : il arrive lire la valeur du compteur (=100) mais n'a pas le temps de l'incrmenter. Les clients A et B sont tous deux en possession d'un compteur gal 100. Supposons que revient le tour du client A : il incrmente son compteur, le passe 101 puis se termine. C'est le tour du client B qui a en sa possession l'ancienne valeur du compteur et non la nouvelle. Il passe donc lui aussi la valeur du compteur 101 et se termine. La valeur du compteur de requtes de l'application est maintenant erron. Pour illuster ce problme, nous reprenons l'application prcdente que nous modifions de la faon suivante : les fichiers [global.asax], [global.asax.vb] et [main.aspx] ne changent pas le fichier [main.aspx.vb] devient le suivant :Imports System.Threading Public Class main Inherits System.Web.UI.Page Protected nbRequtesApplication As Integer Protected nbRequtesClient As Integer Protected jeton As String Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load ' une requte de plus pour l'application et la session ' lecture compteurs nbRequtesApplication = CType(Application.Item("nbRequtes"), Integer) nbRequtesClient = CType(Session.Item("nbRequtes"), Integer) ' attente 5 s Thread.Sleep(5000) ' incrmentation des compteurs nbRequtesApplication += 1 nbRequtesClient += 1 ' enregistrement des compteurs Application.Item("nbRequtes") = nbRequtesApplication Session.Item("nbRequtes") = nbRequtesClient ' init variables de prsentation jeton = Session.SessionID End Sub End Class

L'incrmentation des compteurs a t divise en quatre phases : 1. 2. 3. 4. lecture du compteur mise en sommeil du thread d'excution incrmentation du compteur rcriture du compteur 56/192

Les fondamentaux du dveloppement asp.net

Considrons de nouveau nos deux clients A et B. Entre la phase de lecture et celle d'incrmentation des compteurs de requtes, nous forons le thread d'excution s'arrter pendant 5 secondes. Cela va avoir pour consquence immdiate qu'il va perdre le processeur qui sera alors donn une autre tche. Supposons que le client A passe le premier. Il va lire la valeur N du compteur et tre interrompu pendant 5 secondes. Si pendant celles-ci, le client B dispose du processeur, il devrait lire la mme valeur N du compteur. Au final, les deux clients devraient afficher la mme valeur du compteur, ce qui serait anormal. Nous testons l'application en plaant les quatre fichiers prcdents dans un dossier que nous appelons et nous lanons le serveur Cassini avec les paramtres (,/aspnet/webapplib). Nous prparons deux navigateurs diffrents avec l'url [http://localhost/aspnet/webapplib/main.aspx]. Nous lanons le premier pour qu'il demande l'URL, puis sans attendre la rponse qui arrivera 5 secondes plus tard, on lance le second navigateur. Au bout d'un peu plus de 5 secondes, on obtient le rsultat suivant :

On voit: qu'on a deux clients diffrents (pas le mme jeton de session) que chaque client a fait une requte que le compteur de requtes faites l'application devrait donc tre 2 dans l'un des deux navigateurs. Ce n'est pas le cas. Maintenant, faisons une autre exprience. Avec le mme navigateur, nous lanons cinq requtes l'url [http://localhost/aspnet/webapplib/main.aspx]. L encore, nous les lanons les unes aprs les autres sans attendre les rsultats. Lorsque toutes les requtes ont t excutes, on obtient le rsultat suivant pour la dernire :

On peut remarquer : que les 5 requtes ont t considres comme provenant du mme client car le compteur de requtes client est 5. Non montr ci-dessus, on constate que le jeton de session est effectivement le mme pour les 5 requtes. que le compteur de requtes faites l'application est correct. Qu'en conclure ? Rien de dfinitif. Peut-tre le serveur web ne commence-t-il pas excuter une requte d'un client si celui-ci en a dj une en cours d'excution ? Il n'y aurait donc jamais simultanit d'excution des requtes d'un mme client. Elles seraient excutes les unes aprs les autres. Ce point est vrifier. Il peut en effet dpendre du type de client utilis.

3.1.3.6 Synchronisation des clientsLe problme mis en vidence dans l'application prcdente est un problme classique (mais pas simple rsoudre) d'accs exclusif une ressource. Dans notre problme particulier, il faut faire en sorte que que deux clients A et B ne puissent tre en mme temps dans la squence de code : Les fondamentaux du dveloppement asp.net 57/192

1. 2. 3.

lecture du compteur incrmentation du compteur rcriture du compteur

On appelle une telle squence de code, une squence critique. Elle ncessite une synchronisation des threads amens l'excuter de faon simultane. La palte-forme .NET offre divers outils pour assurer celle-ci. Nous allons ici utiliser la classe [Mutex].

Nous n'utiliserons ici que les constructeurs et mthodes suivants :public Mutex() public bool WaitOne()

public void ReleaseMutex()

cre un objet de synchronisation M Le thread T1 qui excute l'opration M.WaitOne() demande la proprit de l'objet de synchronisation M. Si le Mutex M n'est dtenu par aucun thread (le cas au dpart), il est "donn" au thread T1 qui l'a demand. Si un peu plus tard, un thread T2 fait la mme opration, il sera bloqu. En effet, un Mutex ne peut appartenir qu' un thread. Il sera dbloqu lorsque le thread T1 librera le mutex M qu'il dtient. Plusieurs threads peuvent ainsi tre bloqus en attente du Mutex M. Le thread T1 qui effectue l'opration M.ReleaseMutex() abandonne la proprit du Mutex M. Lorsque le thread T1 perdra le processeur, le systme pourra le donner l'un des threads en attente du Mutex M. Un seul l'obtiendra son tour, les autres en attente de M restant bloqus

Un Mutex M gre l'accs une ressource partage R. Un thread demande la ressource R par M.WaitOne() et la rend par M.ReleaseMutex(). Une section critique de code qui ne doit tre excute que par un seul thread la fois est une ressource partage. La synchronisation d'excution de la section critique peut se faire ainsi :M.WaitOne() ' le thread est seul entrer ici ' section critique .... M.ReleaseMutex()

o M est un objet Mutex. Il faut bien sr ne jamais oublier de librer un Mutex devenu inutile, afin qu'un autre thread puisse entrer dans la section critique son tour, sinon les threads en attente d'un Mutex jamais libr n'auront jamais accs au processeur. Par ailleurs, il faut viter la situation d'interblocage (deadlock) dans laquelle deux threads s'attendent mutuellement. Considrons les actions suivantes qui se suivent dans le temps : un thread T1 obtient la proprit d'un Mutex M1 pour avoir accs une ressource partage R1 un thread T2 obtient la proprit d'un Mutex M2 pour avoir accs une ressource partage R2 le thread T1 demande le Mutex M2. Il est bloqu. le thread T2 demande le Mutex M1. Il est bloqu.

Ici, les threads T1 et T2 s'attendent mutuellement. Ce cas apparat lorsque des threads ont besoin de deux ressources partages, la ressource R1 contrle par le Mutex M1 et la ressource R2 contrle par le Mutex M2. Une solution possible est de demander les deux ressources en mme temps l'aide d'un Mutex unique M. Mais ce n'est pas toujours possible, notamment si cela entrane une mobilisation longue d'une ressource coteuse. Une autre solution est qu'un thread ayant M1 et ne pouvant obtenir M2, relche alors M1 pour viter l'interblocage. Si nous mettons en pratique ce que nous venons d'apprendre, notre application devient la suivante : les fichiers [global.asax] et [main.aspx] ne changent pas le fichier [global.asax.vb] devient le suivant :Imports Imports Imports Imports System System.Web System.Web.SessionState System.Threading

Les fondamentaux du dveloppement asp.net

58/192

Public Class global Inherits System.Web.HttpApplication Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs) ' Se dclenche lorsque l'application est dmarre ' init compteur de clients Application.Item("nbRequtes") = 0 ' cration d'un verrou de synchronisation Application.Item("verrou") = New Mutex End Sub Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs) ' Se dclenche lorsque la session est dmarre ' init compteur de requtes Session.Item("nbRequtes") = 0 End Sub End Class

La seule nouveaut est la cration d'un [Mutex] qui sera utilis par les clients pour se synchroniser. Parce qu'il doit tre accessible tous les clients, il est plac dans l'objet [Application]. le fichier [main.aspx.vb] devient le suivant :Imports System.Threading Public Class main Inherits System.Web.UI.Page Protected nbRequtesApplication As Integer Protected nbRequtesClient As Integer Protected jeton As String Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load ' une requte de plus pour l'application et la session ' on entre dans une section critique - on rcupre le verrou de synchronisation Dim verrou As Mutex = CType(Application.Item("verrou"), Mutex) ' on demande entrer seul dans la section critique qui suit verrou.WaitOne() ' lecture compteurs nbRequtesApplication = CType(Application.Item("nbRequtes"), Integer) nbRequtesClient = CType(Session.Item("nbRequtes"), Integer) ' attente 5 s Thread.Sleep(5000) ' incrmentation des compteurs nbRequtesApplication += 1 nbRequtesClient += 1 ' enregistrement des compteurs Application.Item("nbRequtes") = nbRequtesApplication Session.Item("nbRequtes") = nbRequtesClient ' on permet l'accs la section critique verrou.ReleaseMutex() ' init variables de prsentation jeton = Session.SessionID End Sub End Class

On voit que le client : demande entrer seul dans la section critique. Il demande pour cela la proprit exclusive du Mutex [verrou] il libre le Mutex [verrou] la fin de la section critique afin qu'un autre client puisse entrer son tour dans la section critique. Nous testons l'application en plaant les quatre fichiers prcdents dans un dossier que nous appelons et nous lanons le serveur Cassini avec les paramtres (,/aspnet/webapplic). Nous prparons deux navigateurs diffrents avec l'url [http://localhost/aspnet/webapplic/main.aspx]. Nous lanons le premier pour qu'il demande l'URL puis, sans attendre la rponse qui arrivera 5 secondes plus tard, on lance le second navigateur. Au bout d'un peu plus de 5 secondes, on obtient le rsultat suivant :

Les fondamentaux du dveloppement asp.net

59/192

Cette fois-ci, le compteur de requtes de l'application est correct. On retiendra de cette longue dmonstration, l'absolue ncessit de synchroniser les clients d'une mme application web, s'ils doivent mettre jour des lments partags par tous les clients.

3.1.3.7 Gestion du jeton de sessionNous avons parl de nombreuses fois du jeton de session que s'changeait le client et le serveur web. Rappelons son principe : le client fait une premire requte au serveur. Il n'envoie pas de jeton de session. cause de l'absence du jeton de session dans la requte, le serveur reconnat un nouveau client et lui affecte un jeton. A ce jeton, est galement associ un objet [Session] qui sera utilis pour stocker des informations propres ce client. Le jeton va suivre toutes les requtes de ce client. Il sera inclus dans les enttes HTTP de la rponse faite la premire requte du client. le client connat maintenant son jeton de session. Il va le renvoyer dans les enttes HTTP de chacune des requtes suivantes qu'il va faire au serveur web. Grce au jeton, le serveur pourra retrouver l'objet [Session] attach au client. Pour mettre en vidence ce mcanisme, nous reprenons l'application prcdente en ne modifiant que le seul fichier [main.aspx.vb] :Imports System.Threading Public Class main Inherits System.Web.UI.Page Protected nbRequtesApplication As Integer Protected nbRequtesClient As Integer Protected jeton As String Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load ' une requte de plus pour l'application et la session ' on entre dans une section critique - on rcupre le verrou de synchronisation Dim verrou As Mutex = CType(Application.Item("verrou"), Mutex) ' on demande entrer seul dans la section qui suit verrou.WaitOne() ' lecture compteurs nbRequtesApplication = CType(Application.Item("nbRequtes"), Integer) nbRequtesClient = CType(Session.Item("nbRequtes"), Integer) ' attente 5 s Thread.Sleep(5000) ' incrmentation des compteurs nbRequtesApplication += 1 nbRequtesClient += 1 ' enregistrement des compteurs Application.Item("nbRequtes") = nbRequtesApplication Session.Item("nbRequtes") = nbRequtesClient ' on permet l'accs la section critique verrou.ReleaseMutex() ' init variables de prsentation jeton = Session.SessionID End Sub

Les fondamentaux du dveloppement asp.net

60/192

Private Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Init ' on mmorise la requte du client dans request.txt du dossier de l'application Dim requestFileName As String = Me.MapPath(Me.TemplateSourceDirectory) + "\request.txt" Me.Request.SaveAs(requestFileName, True) End Sub End Class

Lorsque se produit l'vnement [Page_Init], nous sauvegardons la requte du client dans le dossier de l'application. Rappelons quelques points : [TemplateSourceDirectory] reprsente le chemin virtuel de la page en cours d'excution, MapPath(TemplateSourceDirectory) reprsente le chemin physique correspondant. Ceci nous permet de construire le chemin physique du fichier construire, [Request] est un objet reprsentant la requte en cours de traitement. Cet objet a t construit en exploitant la requte brute envoye par le client, c.a.d. une suite de lignes de texte de la forme : Enttes HTTP ligne vide Document

Request.Save([FileName]) sauvegarde la totalit de la requte du client (enttes HTTP et ventuellement le document qui suit) dans un ficier dont le chemin est pass en paramtre.

Nous pourrons donc savoir exactement quelle a t la requte du client. Nous testons l'application en plaant les quatre fichiers prcdents dans un dossier que nous appelons et nous lanons le serveur Cassini avec les paramtres (,/aspnet/session1). Puis avec un navigateur, nous demandons l'URL [http://localhost/aspnet/session1/main.aspx]. Nous obtenons le rsultat suivant :

Nous utilisons le fichier [request.txt] sauvegard par [main.aspx.vb] pour avoir accs la requte du navigateur :GET /aspnet/session1/main.aspx HTTP/1.1 Cache-Control: max-age=0 Connection: keep-alive Keep-Alive: 300 Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Accept-Encoding: gzip,deflate Accept-Language: en-us,en;q=0.5 Host: localhost User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040316

Nous constatons que le navigateur a fait la demande de l'URL [/aspnet/session1/main.aspx], envoy d'autres informations dont nous avons dj parl dans le prcdent chapitre. On n'y voit pas de jeton de session. La page reue en rponse, montre elle que le serveur a cr un jeton de session. On ne sait pas encore si le navigateur l'a reu. Faisons maintenant une seconde requte avec le mme navigateur (Reload). Nous obtenons la nouvelle rponse suivante :

Les fondamentaux du dveloppement asp.net

61/192

Il y a bien un suivi de session puisque le nombre de requtes de la session a t correctement incrment. Voyons maintenant le contenu du fichier [request.txt] :GET /aspnet/session1/main.aspx HTTP/1.1 Cache-Control: max-age=0 Connection: keep-alive Keep-Alive: 300 Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Accept-Encoding: gzip,deflate Accept-Language: en-us,en;q=0.5 Cookie: ASP.NET_SessionId=y153tk45sise0lrhdzrf22m3 Host: localhost User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.7b) Gecko/20040316

On constate que, pour cette deuxime requte, le navigateur a envoy au serveur un nouvel entte HTTP [Cookie:] dfinissant une information appele [ASP.NET_SessionId] et ayant pour valeur le jeton de session qu'on a vu apparatre dans la rponse la premire requte. Grce ce jeton, le serveur web va connecter cette nouvelle requte l'objet [Session] identifi par le jeton [y153tk45sise0lrhdzrf22m3] et retrouver le compteur de requtes associ. On ne sait toujours pas par quel mcanisme, le serveur a envoy le jeton au client car nous n'avons pas accs la rponse HTTP du serveur. Rappelons que celle-ci a la mme structure que la demande du client, savoir un ensemble de lignes de texte de la forme : Enttes HTTP ligne vide Document

Nous avons eu l'occasion d'utiliser un client web qui nous donnait accs la rponse HTTP du serveur web, le client curl. Nous l'utilisons de nouveau, dans une fentre dos, pour interroger la mme url que le navigateur prcdent :E:\curl>curl --include http://localhost/aspnet/session1/main.aspx HTTP/1.1 200 OK Server: Microsoft ASP.NET Web Matrix Server/0.6.0.0 Date: Thu, 01 Apr 2004 07:31:42 GMT X-AspNet-Version: 1.1.4322 Set-Cookie: ASP.NET_SessionId=qxnxmqmvhde3al55kzsmx445; path=/ Cache-Control: private Content-Type: text/html; charset=utf-8 Content-Length: 228 Connection: Close

application-session jeton de session : qxnxmqmvhde3al55kzsmx445
requtes Application : 3
requtes Client : 1

Les fondamentaux du dveloppement asp.net

62/192


Nous avons la rponse notre question. Le serveur web envoie le jeton de session sous la forme d'un entte HTTP [Set-Cookie:] :Set-Cookie: ASP.NET_SessionId=qxnxmqmvhde3al55kzsmx445; path=/

Faisons la mme demande sans renvoyer le jeton de session. On obtient la rponse suivante :E:\curl>curl --include http://localhost/aspnet/session1/main.aspx HTTP/1.1 200 OK Server: Microsoft ASP.NET Web Matrix Server/0.6.0.0 Date: Thu, 01 Apr 2004 07:36:06 GMT X-AspNet-Version: 1.1.4322 Set-Cookie: ASP.NET_SessionId=cs2p12mehdiz5v55ihev1kaz; path=/ Cache-Control: private Content-Type: text/html; charset=utf-8 Content-Length: 228 Connection: Close jeton de session : cs2p12mehdiz5v55ihev1kaz
requtes Application : 4
requtes Client : 1
application-session

Parce que nous n'avons pas renvoy le jeton de session, le serveur n'a pas pu nous identifier et nous a redonn un nouveau jeton. Pour poursuivre une session commence, le client doit renvoyer au serveur le jeton de session qu'il areu. Nous allons le faire ici en utilisant l'option [--cookie cl=valeur] de curl qui va gnrer l'entte HTTP [Cookie: cl=valeur]. Nous avons vu que le navigateur avait envoy cet entte HTTP lors de sa seconde requte.E:\curl>curl --include --cookie ASP.NET_SessionId=cs2p12mehdiz5v55ihev1kaz http://localhost/aspnet/session1/main.aspx

HTTP/1.1 200 OK Server: Microsoft ASP.NET Web Matrix Server/0.6.0.0 Date: Thu, 01 Apr 2004 07:40:20 GMT X-AspNet-Version: 1.1.4322 Cache-Control: private Content-Type: text/html; charset=utf-8 Content-Length: 228 Connection: Close

application-session jeton de session : cs2p12mehdiz5v55ihev1kaz
requtes Application : 5
requtes Client : 2

On remarquera plusieurs choses : le compteur de requtes client a bien t incrment, montrant par l que le serveur a bien reconnu notre jeton. le jeton de session affich par la page est bien celui qu'on a envoy Les fondamentaux du dveloppement asp.net 63/192

le jeton de session n'est plus dans les enttes HTTP envoys par le serveur web. En effet, celui-ci ne l'envoie qu'une fois : lors de la gnration du jeton au dmarrage d'une nouvelle session. Une fois que le client a obtenu son jeton, c'est lui de l'utiliser quand il le veut pour se faire reconnatre.

Rien n'empche un client de jouer avec plusieurs jetons de session, comme le montre l'exemple suivant avec [curl] o nous utilisons le jeton obtenu lors de notre premire requte (requte n 1) :E:\curl>curl --include --cookie ASP.NET_SessionId=qxnxmqmvhde3al55kzsmx445 http://localhost/aspnet/session1/main.aspx

HTTP/1.1 200 OK Server: Microsoft ASP.NET Web Matrix Server/0.6.0.0 Date: Thu, 01 Apr 2004 07:48:47 GMT X-AspNet-Version: 1.1.4322 Cache-Control: private Content-Type: text/html; charset=utf-8 Content-Length: 228 Connection: Close

application-session jeton de session : qxnxmqmvhde3al55kzsmx445
requtes Application : 6
requtes Client : 2

Que signifie cet exemple ? Nous avons envoy un jeton obtenu un peu plus tt. Lorsque le serveur web cre un jeton, il le garde tant que le client associ ce jeton continue lui envoyer des requtes. Aprs un certain temps d'inactivit (20 mn par dfaut avec IIS), le jeton est supprim. L'exemple prcdent montre que nous avons utilis un jeton encore actif. On peut avoir la curiosit de voir quelles ont t les requtes HTTP du client [curl] pendant toutes ces manipulations. Nous savons qu'elles ont t enregistres dans le fichier [request.txt]. Voici la dernire :GET /aspnet/session1/main.aspx HTTP/1.1 Pragma: no-cache Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */* Cookie: ASP.NET_SessionId=qxnxmqmvhde3al55kzsmx445 Host: localhost User-Agent: curl/7.10.8 (win32) libcurl/7.10.8 OpenSSL/0.9.7a zlib/1.1.4

On y trouve bien l'entte HTTP envoyant le jeton de session. Les informations transmises par le serveur via l'entte HTTP [Set-Cookie:] sont appeles des cookies. Le serveur peut utiliser ce mcanisme pour transmettre d'autres informations que le jeton de session. Lorsque le serveur S transmet un cookie un client, il indique galement la dure de vie D de celui-ci et l'URL U associe. Cela signifie pour le client que lorsqu'il demande au serveur S une url de la forme /U/chemin, il peut renvoyer le cookie s'il n'a pas reu celui-ci depuis un temps suprieur D. Rien n'empche un client de ne pas observer ce code de dontologie. Les navigateurs eux le respectent. Certains navigateurs donnent accs au contenu des cookies qu'ils reoivent. C'est le cas du navigateur Mozilla. Voici par exemple les informations lies au cookie envoy par le serveur dans un exemple prcdent :

Les fondamentaux du dveloppement asp.net

64/192

On y trouve : le nom du cookie [ASP.NET_SessionId] sa valeur [y153...m3] la machine laquelle il est associ [localhost] l'url laquelle il est associ [/] sa dure de vie [at end of session] Le navigateur enverra donc le jeton de session chaque fois qu'il demandera une URL de la forme [http://localhost/...], c.a.d. chaque fois qu'il demandera une url au serveur web de la machine [localhost]. La dure de vie du cookie est celle de la session. Pour le navigateur, cela entrane que le cookie n'expire jamais. Il l'enverra chaque fois qu'il demandera une url de la machine [localhost]. Ainsi si le navigateur reoit le jeton de session le jour J, qu'on le ferme et qu'on le rutilise le lendemain, il renverra alors le jeton de session (qui a t conserv dans un fichier). Le serveur recevra ce jeton que lui n'a plus, car un jeton de session a une dure de vie limite sur le serveur (20 mn sur IIS). Aussi dmarrera-t-il une nouvelle session. Il est possible d'inhiber l'utilisation des cookies sur un navigateur. Dans ce cas, le client reoit bien le jeton de session mais ne le renvoie pas ce qui empche le suivi de session. Pour le montrer, nous inhibons l'utilisation des cookies sur notre navigateur (Mozilla ici) :

Par ailleurs, nous supprimons tous les cookies existant :

Ceci fait, nous relanons le serveur Cassini pour repartir de zro et avec le navigateur, nous demandons de nouveau l'url [http://localhost/aspnet/session1/main.aspx] : Les fondamentaux du dveloppement asp.net 65/192

Regardons si notre navigateur a stock un cookie :

Nous constatons que le navigateur n'a pas stock le cookie du jeton de session que le serveur lui a envoy. On peut donc s'attendre ce qu'il n'y ait pas de suivi de session. Nous redemandons la mme url (Reload) :

On a bien ce qui tait attendu. Le navigateur n'a pas renvoy le jeton de session, qu'il avait pourtant reu mais pas stock. Le serveur a donc commenc une nouvelle session avec un nouveau jeton. On retiendra de cet exemple que notre politique de suivi de session est mise mal si l'utilisateur a inhib l'utilisation des cookies sur son navigateur. Il y a cependant une autre faon que les cookies, d'changer le jeton de session entre serveur et client. Il est en effet possible de signaler au serveur web que l'application travaille sans cookie. Cela se fait au moyen du fichier de configuration [web.config] :

Le fichier de configuration ci-dessus indique que l'application va travailler sans cookies (cookieless="true") et que la dure d'inactivit maximale d'un jeton de session est de 10 mn (timeout="10"). Aprs ce dlai, la session associe au jeton est dtruite. Le processus d'change du jeton de session entre le serveur et le client va tre le suivant : 1. le client demande l'url [http://machine:port/V/chemin] o V est un dossier virtuel du serveur web 2. le serveur gnre un jeton J et rpond au client de se rediriger vers l'url [http://machine:port/V/(J)/chemin]. Il a donc plac le jeton dans l'url interroger, immdiatement derrire le dossier virtuel V 3. le client obit cette redirection et demande la nouvelle URL [[http://machine:port/V/(J)/chemin]. 4. le serveur rpond cette demande et envoie une page de rponse. Illustrons ces diffrents points. Nous mettons la totalit de l'application prcdente dans un nouveau dossier . Nous plaons dans ce mme dossier le fichier [web.config] prcdent. Par ailleurs, nous modifions le code de prsentation [main.aspx] pour y inclure un lien : application-session jeton de session :
requtes Application :
requtes Client :

Les fondamentaux du dveloppement asp.net

66/192


Recharger l'application

Ce lien pointe sur la page [main.aspx] et est donc quivalent au bouton (Reload) du navigateur. Le serveur Cassini est lanc avec les paramtres (,/session2). Nous drogeons notre habitude qui consistait noter le dossier virtuel [/aspnet/XX]. En effet, cause de l'insertion du jeton de session dans l'url, le dossier virtuel ne doit avoir qu'un lment /XX. Nous utilisons tout d'abord le client [curl] pour demander l'url [http://localhost/session2/main.aspx] :E:\curl>curl --include http://localhost/session2/main.aspx HTTP/1.1 302 Found Server: Microsoft ASP.NET Web Matrix Server/0.6.0.0 Date: Thu, 01 Apr 2004 13:52:36 GMT X-AspNet-Version: 1.1.4322 Location: /session2/(hinadjag3bt0u155g5hqe245)/main.aspx Cache-Control: private Content-Type: text/html; charset=utf-8 Content-Length: 163 Connection: Close Object moved Object moved to here

Nous voyons que le serveur rpond par l'entte HTTP [HTTP/1.1 302 Found] au lieu de [HTTP/1.1 200 OK]. C'est une entte qui demande au client de se rediriger vers l'url indique par l'entte HTTP Location [Location: /session2/(hinadjag3bt0u155g5hqe245)/main.aspx]. On voit le jeton de session qui a t insr dans l'url de redirection. Un navigateur recevant cette rponse, demande la nouvelle url de faon transparente pour l'utilisateur qui ne voit pas la nouvelle requte. Au cas o le navigateur ne grerait pas seul la redirection, un document HTML est envoy derrire le code HTTP cidessus. On y trouve un lien sur l'url de redirection, lien sur lequel l'utilisateur pourra cliquer. Maintenant, faisons la mme chose avec un navigateur o les cookies ont t inhibs. Nous demandons l encore, l'url [http://localhost/session2/main.aspx]. Nous obtenons la rponse suivante du serveur :

Tout d'abord, constatons que l'url affiche par le navigateur n'est pas celle que nous avons demande. C'est le signe qu'une redirection a eu lieu. En effet, le navigateur affiche toujours l'URL du dernier document reu. Si donc, il n'affiche pas l'url [http://localhost/session2/main.aspx], c'est qu'on lui a demand de se rediriger vers une autre url. Il peut y avoir plusieurs redirections. L'url affiche par le navigateur est l'url de la dernire redirection. Nous pouvons constater que le jeton de session est prsent dans l'url affiche par le navigateur. On peut le voir car ce jeton est galement affich par notre programme dans la page. Rappelons le code du lien qui a t plac dans la page :Recharger l'application

C'est un lien relatif puisqu'il ne commence pas par le signe / qui en ferait un lien absolu. Relatif quoi ? Pour comprendre ce point, il faut revenir l'url du document actuellement affich : [http://localhost/session2/(gu5ee455pkpffn554e3b1a32)/main.aspx]. Les liens relatifs qui seront trouvs dans ce document seront relatifs au chemin [http://localhost/session2/(gu5ee455pkpffn554e3b1a32)]. Ainsi notre lien ci-dessus est-il quivalent au lien :Recharger l'application

C'est ce que nous montre le navigateur si on passe la souris sur le lien :

Les fondamentaux du dveloppement asp.net

67/192

Si nous cliquons sur le lien [Recharger l'application], c'est donc l'url [http://localhost/session2/(gu5ee455pkpffn554e3b1a32)/main.aspx] qui est appele. Le serveur va donc recevoir le jeton de session et pouvoir retrouver les informations qui lui sont lies. C'est ce que nous montre sa rponse rveur :

Nous retiendrons que si nous avons besoin de faire un suivi de session dans une application web et que nous ne sommes pas srs que les navigateurs clients de cette application vont autoriser l'utilisation des cookies, alors on doit configurer l'application pour qu'elle travaille sans cookies les pages de l'application doivent comporter des liens relatifs et non absolus

3.2 Rcuprer les informations d'une requte client3.2.1 Le cycle requte-rponse du client-serveur webRappelons ici le contexte client-serveur d'une application web : APPLICATION A client-1A client-2A Serveur WEB global.asax page-1A.aspx page-2A.aspx code ApplicationA Session-1A donnes La requte d'un client pour une application web est traite de fa faon suivante : 1. le client ouvre une connexion tcp-ip vers un port P du service web de la machine M abritant l'application web 2. il envoie sur cette connexion une suite de lignes de texte selon le protocole HTTP. Cet ensemble de lignes forme ce qu'on appelle la requte du client. Elle a la forme suivante : Enttes HTTP ligne vide Document Une fois la demande envoye, le client va attendre la rponse. 3. la premire ligne des enttes HTTP prcise l'action demande au serveur web. Elle peut avoir plusieurs formes : 68/192 Session-2A .aspx

Les fondamentaux du dveloppement asp.net

o o o

GET url HTTP/, avec gal actuellement 1.0 ou 1.1. Dans ce cas, la requte ne comprend pas la partie [Document] POST url HTTP/. Dans ce cas, la requte comprend une partie [Document], le plus souvent une liste d'informations destination de l'application web PUT url HTTP/. Le client envoie un document dans la partie [Document] et veut le stocker sur le serveur l'adresse url

4.

5.

Lorsque le client souhaite transmettre des informations l'application web laquelle il s'est connect, il dispose principalement de deux moyens : o sa demande est [GET url_enrichie HTTP/] o url_enrichie est de la forme [url?param1=val1&param2=val2&...]. Le client transmet outre l'url, une srie d'informations sous la forme [cl=valeur]. o sa demande est [POST url HTTP/]. Dans la partie [Document], il transmet des informations sous la mme forme que prcdemment : [param1=val1&param2=val2&...]. sur le serveur, l'ensemble de la chane de traitement de la requte du client a accs celle-ci via un objet global appel Request. Le serveur web a plac dans cet objet la totalit de la requte du client sous une forme que nous allons dcouvrir. L'application sollicite va traiter cet objet et construire une rponse au client. Celle-ci est disponible dans un objet global appel Response. Le rle de l'application web est de construire un objet [Response] partir de l'objet [Request] reu. La chane de traitement dispose galement des objets globaux [Application] et [Session] dont nous avons dj parl et qui vont lui permettre de partager des donnes entre clients diffrents (Application) ou entre requtes successives d'un mme client (Session). l'application va envoyer sa rponse au serveur au moyen de l'objet [Response]. Celle-ci, une fois sur le rseau aura la forme HTTP suivante : Enttes HTTP ligne vide Document Une fois cette rponse envoye, le serveur va fermer la connexion rseau en rception (sauf si le client lui a dit de ne pas le faire). le client va recevoir la rponse et va fermer son tour la connexion (en mission). Ce qui sera fait de cette rponse dpend du type du client. Si celui-ci est un navigateur, et que le document reu est un document HTML, celui-ci sera affich. Si le client est un programme, la rponse va tre analyse et exploite. Le fait qu'aprs le cycle requte-rponse, la connexion qui liait le client au serveur soit ferme fait du protocole HTTP un protocole sans tat. Lors de la requte suivante, le client tablira une nouvelle connexion rseau au mme serveur. Du fait que ce n'est plus la mme connexion rseau, le serveur n'a aucune possibilit (au niveau tcp-ip et HTTP) de lier cette nouvelle connexion une prcdente. C'est le systme du jeton de session qui permettra ce lien.

6. 7.

3.2.2 Rcuprer les informations transmises par le clientNous examinons maintenant certaines proprits et mthodes de l'objet [Request] qui permet au code de l'application d'avoir accs la requte du client et donc aux informations qu'il a transmises. L'objet [Request] est de type [HttpRequest] :

Cette classe a de nombreuses proprits et mthodes. Nous nous intressons aux proprits HttpMethod, QueryString, Form et Params qui vont nous permettre d'avoir accs aux lments de la chane d'informations [param1=val1&param2=val2&...].HttpMethod as String QueryString as NameValueCollection Form as NameValueCollection Params as NameValueCollection

mthode de requte du client : GET, POST, HEAD, ... collection des lments de la chane de requte param1=val1&param2=val2&.. de la 1re ligne HTTP [mthode]?param1=val1&param2=val2&... o [mthode] peut tre GET, POST, HEAD. collection des lments de la chane de requte param1=val1&param2=val2&.. se trouvant dans la partie [Document] de la requte (mthode POST). rassemble plusieurs collections : QueryString, Form, ServerVariables, Cookies au sein d'une unique collection. 69/192

Les fondamentaux du dveloppement asp.net

3.2.3 Exemple 1Mettons en oeuvre ces lments sur un premier exemple. L'application n'aura qu'un lment [main.aspx]. Le code de prsentation [main.aspx] sera le suivant : Requte client Requte :
nom :
ge :

La page affiche trois informations [mthode, nom, age] calcules par sa partie contrleur [main.aspx.vb] :Public Class main Inherits System.Web.UI.Page Protected nom As String = "xx" Protected age As String = "yy" Protected mthode As String Private Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Init ' on mmorise la requte du client dans request.txt du dossier de l'application Dim requestFileName As String = Me.MapPath(Me.TemplateSourceDirectory) + "\request.txt" Me.Request.SaveAs(requestFileName, True) End Su