menu
  Home  ==>  articles  ==>  web  ==>  asp_net  ==>  delphi_asp_net_tutorial   

Delphi ASP.NET Tutorial - John COLIBRI.


1 - Introduction

Ce tutorial va présenter les principales technique pour construire des application Internet utilisant Asp.Net:
  • nous commencerons par détailler une première application simple.
  • après la première application simple, nous décrirons l'architecture ASP.NET
  • puis nous présenterons quelques techniques couramment utilisées: afficher sur la page .HTML, formater ces données, effectuer des transferts de page, valider la saisie
  • nous terminerons par la lecture et la modifier des données provenant d'une base de données, en particulier avec une DataGrid
Ce tutoriel présente les manipulations en détail, et les codes sources sont téléchargeables (télécharger les sources).

Si après ce premier contact vous souhaitez approfondir vos connaissances, nous vous proposons:

Nous nous adressons pour ce tutorial à un programmeur Delphi:
  • ayant une idée élémentaire de Delphi: Palette, Inspecteur, OnClick. Tout le reste sera expliqué
  • n'ayant pas nécessairement de connaissance de programmation Asp, Asp.Net ou Internet



2 - La première application Asp.Net

2.1 - Installation préalable

Nous supposons que vous avez installé Delphi (Delphi 8, Delphi 2005 ou Delphi 2006).

Si vous utilisez Delphi 8 ou Delphi 2005, il faut aussi installer le serveur de développement Cassini. Si Cassini n'est pas installé, voyez l'article Installation Cassin qui indique comment procéder, et comment vérifier que l'installation est correcte. Pour Delphi 2006, le serveur est déjà installé par Delphi.



2.2 - La Première application

Notre première application va
  • afficher une page comportant un petit mot de bienvenu, une boîte de saisie du nom et un bouton pour envoyer son nom au Serveur
  • l'utilisateur est censé taper son nom et cliquer le bouton
  • le Serveur renverra alors un remerciement


Voici comment créer cette application:
   choisissez un répertoire où seront placées les pages ASP. Nous avons choisi

C:\programs\fr\asp_web\asp_net\tutorial\p_11_first_asp_net

   lancez Delphi
   sélectionnez "fichier | new | asp.net Web application"

asp net application

   Delphi présente un dialogue nous demandant où se trouve notre application et quel serveur web nous souhaitons utiliser.

   Nous plaçons notre chemin et sélectionons CASSINI

   voici nos paramètres

asp net
directory

   confirmez

   Delphi présente la forme ASP vierge

   compilez et exécutez

   Delphi compile, et lance automatiquement le serveur Web local Cassini:

cassini is started

et Cassini appelle Internet Explorer en fournissant l'adresse de notre page:

inernet explorer

   fermez Internet Explorer
   Cassini se ferme, et Delphi reprend la main en mode conception


Maintenant que nous avons vérifié que l'installation est correcte, nous remplissons la page avec quelques éléments.



Pour écrire du texte libre sur la page .HTML, nous utilisons la propriété Response de la Forme, et sa méthode Write:

Response.Write('Hello')

Nous écrivons notre texte dans le premier événement disponible, qui est Page_Load. Cet événement, un peu similaire à un OnActivate de Win32, est pré-créé par Delphi. Il suffit donc de placer nos écritures dans cet événement. Et pour distinguer la première requête de la réponse au click du bouton, nous utilisons la fonction de test IsPostBack.

Par conséquent:
   sélectionnez l'onglet .PAS de l'éditeur

inernet explorer

   dans l'événement Page_Load (déjà créé par Delphi), ajoutez le code qui écrit soit le message de bienvenu, soit le message d'adieu:

procedure t_11_first_asp_net.Page_Load(senderSystem.Object
    eSystem.EventArgs);
  begin
    if IsPostBack
      then Response.Write('ok ')
      else Response.Write('Hello <BR>');
  end// Page_Load



A présent, posons la boîte où l'utilisateur tapera son nom:
   sélectionnez l'onglet "Design" de l'Editeur
   de l'onglet "web contols" de la Palette, sélectionnez et déposez une TextBox

textbox controls



Puis un bouton qui permettra à l'utilisateur d'envoyer son nom vers le Serveur:
   de ce même onglet, sélectionnez un Button et déposez-le sur la Forme

textbox controls

Renommez le bouton submit_button. Puis créez son événement Click et écrivez au-revoir, par exemple:

procedure t_11_first_asp_net.submit_button_Click(senderSystem.Object
    eSystem.EventArgs);
  begin
    Response.Write('welcome 'name_textbox.Text'<BR>');
    name_textbox.Visible:= False;
    submit_button.Text:= 'Bye';
  end// submit_button_Click

   Compilez et exécutez

   Delphi compile, puis lance Cassini, qui lance Internet Explorer

request answer

   tapez un nom, par exemple Sam et clickez "submit"

   Internet Explorer envoie "Sam" à Cassini, qui retourne la réponse suivante:

submit answer




3 - Fonctionnement Asp.Net

3.1 - Fonctionnement Asp.Net

Représentons d'abord graphiquement les transferts de données entre le Client et le Serveur:
  • au départ, le Serveur contient les fichiers .ASPX et .PAS (renommés e.aspx et e.pas pour simplifier la figure):

    asp_net_start

  • l'utilisateur charge Internet Explorer et demande notre page

    asp_net_start

  • Cassini construit la réponse et l'envoie à Internet Explorer

    asp
net response

  • l'utilisateur tape "Sam" et clique "send"

    asp net response

  • Cassini reçoit cette soumission, construit puis renvoie sa réponse:

    asp net submit response



3.2 - Les données échangées

Voici, capturé à l'aide de l'utilitaire Cassini Spy les paquets Tcp/Ip échangés entre Internet Explorer et Cassini:
   l'utilisateur envoie sa requête:

 
    -> | GET /p_11_first_asp_net/a_11_first_asp_net.aspx HTTP/1.1
    -> | Accept: */*
    -> | Accept-Language: fr
    -> | Accept-Encoding: gzip, deflate
    -> | User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
    -> | Host: localhost:81
    -> | Connection: Keep-Alive
    -> | 

   Cassini renvoie la page:

 
 <-    | HTTP/1.1 200 OK
 <-    | Server: Cassini/1.0.0.0
 <-    | Date: Tue, 21 Mar 2006 04:43:08 GMT
 <-    | X-AspNet-Version: 1.1.4322
 <-    | Set-Cookie: ASP.NET_SessionId=spedsu55n5w2xyekicwqbs3d; path=/
 <-    | Cache-Control: private
 <-    | Content-Type: text/html; charset=utf-8
 <-    | Content-Length: 564
 <-    | Connection: Close
 <-    | 
 <-    | Hello <BR>
 <-    | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <-    | 
 <-    | <html>
 <-    |   <head>
 <-    |     <title></title>
 <-    |   </head>
 <-    | 
 <-    |   <body>
 <-    |      <form name="_ctl0" method="post" action="a_11_first_asp_net.aspx" id="_ctl0">
 <-    |       <input type="hidden" name="__VIEWSTATE" value="dDwyMDE4OTI5MDg4Ozs+u3wNIkzaGHMAC1thTPRREuxDXd8=" />
 <-    | 
 <-    |       <input name="name_textbox" type="text" id="name_textbox" style="width:137px;" />
 <-    |       <input type="submit" name="submit_button" value="send" id="submit_button" style="width:103px;" />
 <-    |      </form>
 <-    |   </body>
 <-    | </html>
 <-    | 

   l'utilisateur tape "Sam" et clique "send":

 
    -> | POST /p_11_first_asp_net/a_11_first_asp_net.aspx HTTP/1.1
    -> | Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */*
    -> | Referer: http://localhost:81/p_11_first_asp_net/a_11_first_asp_net.aspx
    -> | Accept-Language: fr
    -> | Content-Type: application/x-www-form-urlencoded
    -> | Accept-Encoding: gzip, deflate
    -> | User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
    -> | Host: localhost:81
    -> | Content-Length: 109
    -> | Connection: Keep-Alive
    -> | Cache-Control: no-cache
    -> | Cookie: ASP.NET_SessionId=spedsu55n5w2xyekicwqbs3d
    -> | 
    -> | __VIEWSTATE=dDwyMDE4OTI5MDg4Ozs%2Bu3wNIkzaGHMAC1thTPRREuxDXd8%3D&name_textbox=sam&submit_button=send

   Cassini renvoie la réponse:

 
 <-    | HTTP/1.1 200 OK
 <-    | Server: Cassini/1.0.0.0
 <-    | Date: Tue, 21 Mar 2006 04:43:27 GMT
 <-    | X-AspNet-Version: 1.1.4322
 <-    | Cache-Control: private
 <-    | Content-Type: text/html; charset=utf-8
 <-    | Content-Length: 626
 <-    | Connection: Close
 <-    | 
 <-    | ok welcome sam<BR>
 <-    | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 <-    | 
 <-    | <html>
 <-    |   <head>
 <-    |     <title></title>
 <-    |   </head>
 <-    | 
 <-    |   <body>
 <-    |      <form name="_ctl0" method="post" action="a_11_first_asp_net.aspx" id="_ctl0">
 <-    |       <input type="hidden" name="__VIEWSTATE" value="dDwyMDE4OTI5MDg4O3Q8O2w8aTwxP
js+O2w8dDw7bDxpPDE+O2k8Mz47PjtsPHQ8cDxwPG
w8VGV4dDtWaXNpYmxlOz47bDxzYW07bzxmPjs+Pjs+O
zs+O3Q8cDxwPGw8VGV4dDs+O2w8QnllOz4+Oz47Oz
47Pj47Pj47PiZZfJnzAsTbvXefogRPoxfeaeXi
" />
 <-    |       <input type="submit" name="submit_button" value="Bye" id="submit_button" style="width:103px;" />
 <-    |      </form>
 <-    |   </body>
 <-    | </html>
 <-    | 

Quelques remarques:
  • les données échangées sont très similaires à celles qui l'auraient été si nous avions utilisé CGI ou ISAPI:
    • les données fournies par l'utilisateur sont dans une balise <FORM>...</FORM>
    • la soumission est envoyée par POST
  • le champ caché __VIEWSTATE est le seul élément nouveau. Il contient en fait l'état de la communication, et permet essentiellement d'éviter au Serveur de recharger à chaque soumission les données d'une base de données (si la page avait chargées des données depuis une base, ce qui n'est pas le cas ici).
    Nous avons fourni ailleurs un Analyseur de ViewState, et, voici à titre d'exemple le contenu du ViewState retournée par la dernière réponse de Cassini:
    • le ViewState de départ:

       
      dDwtMjA0ODIyNzQyMjt0PDtsPGk8MT47PjtsPHQ8O2w8a
      TwxPjtpPDM+Oz47bDx0PHA8cDxsPFRleHQ7VmlzaWJsZT
      s+O2w8U2FtO288Zj47Pj47Pjs7Pjt0PHA8cDxsPFRleHQ
      7PjtsPEJ5ZTs+Pjs+Ozs+Oz4+Oz4+Oz56mm3pdEpYbpOt
      OuxkEew1uLqgpQ==

    • voici le contenu décodé:

       
      t<-2048227422;t<;l<i<1>;>;l<t<;l<i<1>;i<3>;>;
      l<t<p<p<l<Text;Visible;>;l<Sam;o<f>;>>;>;;>;
      t<p<p<l<Text;>;l<Bye;>>;>;;>;>>;>>;>
      zšmétJXnô­:ìdì5¸º ¥|

    • et voici son contenu après analyse:

       
      tree_hash -2048227422
        control 1
          [1] Text=Sam, Visible=False,
          [3] Text=Bye,

    Dans notre cas, le ViewState n'apporte rien, mais pour des pages contenant des informations provenant de bases de données, il encode les informations qui ne sont pas déjà stockées dans les champs .HTML standards


3.3 - Fonctionnement Asp.Net

Si les données échangées sont traditionnelles, la génération des pages envoyées au Client en revanche est remarquable.

Pour bien distinguer les liens entre les différents éléments, nous avons renommé les fichiers:

  • le nom du répertoire, qui est automatiquement celui du projet Delphi est p_11_first_asp_net
  • dans le gestionnaire de projet, nous avons renommé WebForm1.aspx, l'unité contenant le code, a_11_first_asp_net.aspx:

    aspx renaming

  • dans l'analyseur de structure (en haut à gauche), nous avons renommé la CLASS tWebForm1

    rename the asp class name



Dans ces conditions, le répertoire de notre projet contient les fichiers suivants:

asp net files

Et:

  • p_11_first_asp_net.dpr ( *.bdsproj, *.cfg, *.identcache, *.rps) est le projet principal
  • Global.Asax et Global.Pas correspondent à des traitements que nous pouvons éventuellement surcharger pour intervenir avant les traitements de notre page. Nous ne présenterons pas ces événements dans ce tutoriel
  • Web.Config est un fichier de paramétrage de l'application
  • les .DCUIL sont les fichiers de compilation intermédiaires
  • le code .PAS contient le traitement de nos événements:

    unit a_11_first_asp_net;
      interface
        uses
          System.CollectionsSystem.ComponentModel,
          System.DataSystem.DrawingSystem.WebSystem.Web.SessionState,
          System.Web.UISystem.Web.UI.WebControlsSystem.Web.UI.HtmlControls;

        type
          t_11_first_asp_net = class(System.Web.UI.Page)
            strict private
              procedure InitializeComponent;
              procedure submit_button_Click(senderSystem.ObjecteSystem.EventArgs);
            strict private
              procedure Page_Load(senderSystem.ObjecteSystem.EventArgs);
            strict protected
              name_textboxSystem.Web.UI.WebControls.TextBox;
              submit_buttonSystem.Web.UI.WebControls.Button;
              procedure OnInit(eEventArgs); override;
            private
            public
          end// t_11_first_asp_net

      implementation

        procedure t_11_first_asp_net.InitializeComponent;
          begin
            Include(Self.submit_button.ClickSelf.submit_button_Click);
            Include(Self.LoadSelf.Page_Load);
          end// InitializeComponent

        procedure t_11_first_asp_net.OnInit(eEventArgs);
          begin
            InitializeComponent;
            inherited OnInit(e);
          end// OnInit

        procedure t_11_first_asp_net.Page_Load(senderSystem.Object;
            eSystem.EventArgs);
          begin
            if IsPostBack
              then Response.Write('ok ')
              else Response.Write('Hello <BR>');
          end// Page_Load

        procedure t_11_first_asp_net.submit_button_Click(senderSystem.Object;
            eSystem.EventArgs);
          begin
            Response.Write('welcome 'name_textbox.Text'<BR>');
            name_textbox.Visible:= False;
            submit_button.Text:= 'Bye';
          end// submit_button_Click

        end.

  • et le contenu du fichier .ASPX est le suivant:

     
    <%@ Page language="c#" Debug="true"
        Codebehind="a_11_first_asp_net.pas"
        AutoEventWireup="false"
        Inherits="a_11_first_asp_net.t_11_first_asp_net" %>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
      <head>
        <title></title>
      </head>
      <body>
         <form runat="server">
          <ASP:TextBox id="name_textbox" runat="server" width="137px">
          </ASP:TextBox>
          <ASP:Button id="submit_button" runat="server" width="63px" text="send">
          </ASP:Button>
         </form>
      </body>
    </html>



La partie la plus intéressante est celle contenue dans le fichier .ASPX:
  • il est très similaire au fichier .HTML envoyé au Client, mais avec des annotations utilisées pour la génération de ce fichier .HTML
  • la première ligne < %@ Page est une "directive asp.net" qui indique, entre autre
    • que les événements seront traités par notre fichier Pas
          Codebehind="a_11_first_asp_net.pas"  
    • que la CLASSe qui effectuera le traitement va hériter de:
          Inherits="a_11_first_asp_net.t_11_first_asp_net"  
    La CLASS que nous utilisons est déclarée par:

    type t_11_first_asp_net = class(System.Web.UI.Page)

    Donc:

    • notre CLASS hérite de tPage (l'équivalent de tForm en Win32)
    • Asp.Net va utiliser notre classe comme ancêtre pour construire la CLASS réelle qui va générer la page
  • dans le reste du fichier .ASPX
    • les parties runat="server" indiquent que les événements seront traités au niveau du Serveur Cassini (pas par Client Internet Explorer)
    • les balises < ASP: contiennent les contrôles de la page


Pour résumer:
  • le fichier .ASPX contient une sorte de "modèle" de la page. C'est une sorte de .DFM contenant l'ébauche de ce qui sera généré
  • le fichier .PAS contient le code, qui sera utilisé
    • pour générer du texte .HTML (Response.Write ...)
    • pour traiter les événement. Lorsque l'utilisateur clique sur un Button, l'information sera retournée vers Cassini, l'événement OnClick exécuté, et ce traitement participera au contenu de la nouvelle page .HTML


Si Asp.Net créé une nouvelle CLASSe à partir ne notre CLASSe t_11_first_asp_net, où est-elle ? Nous ne la verrons jamais. Asp.Net créé cette nouvelle classe, la compile sur disque et exécute son code. Ce code est placé dans le répertoire BIN sous le nom de p_11_first_asp_net.DLL



Voici à présent le film des événements:

  • nous créons notre application (le fichier .PAS et le fichier .ASPX)

    asp net start

  • l'utilisateur demande notre page depuis Internet Explorer

    asp net start

  • Cassini va
    • charger le .PAS et le .ASPX
    • créer la nouvelle CLASSe (nommée t_xxx), que nous ne verrons pas en source
    • compiler le tout dans une Assembly .Net (nommée ici e.dll), qui va être stockée dans le répertoire BIN sous le nom de p_11_first_asp_net.DLL
    • une instance de la classe (c_xxx) va être créée, qui comportera l'arbre des contrôles de notre page (en programmation objet, il y a le type, le code et les données)
    • la page .HTML sera construite par le code à partir de ces données mémoire, et l'ensemble va être envoyé à Internet Explorer

    asp net start

    Une fois les données expédiées, les données mémoire sont libérées

  • si l'utilisateur clique sur le Bouton, une seconde requête va être envoyée à Cassini:

    asp net start

  • Cassini va:
    • recharger l'Assembly (e.dll) en économiser ainsi une compilation
    • créer l'instance de la CLASSe et reconstruire en mémoire l'arbre des contrôles de notre page
    • mettre les données des contrôle à jour avec les valeurs provenant de l'utilisateur ("Sam" dans notre cas). Cet arbre correspond maintenant exactement aux données telles que les voit le Client
    • à l'aide de ces données actualisées, les codes correspondant à l'événement Client (le click de "send") est exécuté
    • le contenu de la page est envoyé au Client

    asp net start

    Une fois les données expédiées, les données mémoire sont libérées

  • le cycle continue ensuite: soumission du Client, réponse de Cassini


Pour résumer le fonctionnement
  • nous plaçons des contrôles dont les paramètres sont mémorisés dans .ASPX. Nous pourrions ajouter des fioritures graphiques ou autres artifices de présentations à ce fichier: le tout sera intégré à la page que sera générée par la suite
  • nous écrivons dans le fichier .PAS
    • les traitements à effectuer à la création dans t_page.OnInit
    • les traitements à effectuer lorsque tous les contrôles sont chargés et mis à jour dans t_page.Page_Load. La fonction IsPostback nous permet de distinguer la première génération des réponses aux "submit"
    • les traitements à effectuer en réaction aux actions de l'utilisateur dans les événements des contrôles. Notez bien que le "clic" est effectué dans Internet Explorer, mais les traitements correspondants sont effectués sur le Serveur, qui renverra la réponse à Internet Explorer
Asp.Net permet donc une séparation très agréable entre:
  • la partie présentation dans Asp.Net. C'est le domaine des graphistes et autres stylistes. L'entrée des artistes
  • le code de traitement dans le fichier .PAS, et en mode objet (classes, événements, héritage etc). Ici, c'est le royaume du développeur.


Voyons à présente quelques autres exemples de traitement Asp.Net.




4 - Quelques Traitements courants

4.1 - Ecrire des données

Pour ajouter du texte à la page générée, nous utilisons Response.Write. Ces instructions peuvent être placées dans n'importe quel événement appelé après que l'arbre des contrôle ait été construit et initialisé (après Page_Load)



4.2 - Transfert de Page

Dans notre premier exemple, dans la réponse au "clic" nous avons rendu le TextBox invisible pour mieux présenter la réponse. Une meilleure solution consiste à envoyer une autre page pour la réponse.

Plusieurs techniques existent pour renvoyer à l'utilisateur une page différente de la page dans laquelle il vient de cliquer: la redirection et le transfert.



Pour la première technique:

  • dans la construction de la réponse, la première page appelle Response.Redirect, en ajoutant à l'URL destination les paramètres en suivant une syntaxe style CGI:

    Response.Redirect(url?clé_1=valeur_1&clé_2=valeur_2&clé_3=valeur_3 ...)

  • la page destinataire lit les paramètres en utilisant la propriété Request de la page et sa liste QueryString, avec la syntaxe suivante:

    valeur_1:= Request.QueryString[clé_1];
    valeur_2:= Request.QueryString[clé_2];
    valeur_3:= Request.QueryString[clé_3];

Voici l'exemple:
   lancez Delphi, sélectionnez "fichier | new | asp.net Web application" et tapez le nom et le répertoire de la nouvelle application

C:\programs\fr\asp_web\asp_net\tutorial\p_21_redirect_asp_net

   Delphi présente la forme ASP vierge

   compilez et exécutez

   ajoutez une Textbox, nommez-la name_textbox, et un Button, appelé submit_button
   dans Page_Load redirigez la réponse vers une seconde page:

procedure T_21_redirect_asp_net.Page_Load(senderSystem.Object;
    eSystem.EventArgs);
  begin
    if IsPostBack
      then Response.Redirect('a_21_bye.aspx?customer='name_textbox.Text);
  end// Page_Load

   créez une seconde page, en sélectionnant "File | New | Other", puis

new asp net page

   Delphi crée un nouvel ensemble .ASPX / .PAS

   posez un Label sur cette nouvelle Forme

Dans l'événement Page_Load de cette page, affichez le message d'adieu:

procedure T_21_bye_form.Page_Load(senderSystem.Object;
    eSystem.EventArgs);
  begin
    Label1.Text:= 'Bye 'Request.QueryString['customer'];
  end// Page_Load

   compilez et exécutez. Tapez "sam" dans la TextBox, et cliquez "send"
   voici la page d'adieu:

redirect asp net response

Notez que:
  • les paramètres apparaissent dans la requête (la combo box Adresse ci-dessus), ce qui peut être une limitation.
  • d'autre part, la technique qui consiste à envoyer un client un ordre de redirection est fort ancienne et est inclue dans .HTTP. Elle a l'inconvénient de renvoyer au Client la demande de redirection, et c'est le Client qui va demander la nouvelle page. Il paraît plus simple de demander au Serveur de directement renvoyer la nouvelle page. C'est ce que la technique qui suit va permettre.


La méthode Transfert fonctionne ainsi:
  • la première page dépose les paramètres dans la liste Context.Items:

    Context.Items.Add(clé_1valeur_1);
    Context.Items.Add(clé_2valeur_2);
    Context.Items.Add(clé_3valeur_3);

    Server.Transfer(url);

  • la seconde page lit les paramètres de Context.Items

    valeur_1:= Context.Items[clé_1];
    valeur_2:= Context.Items[clé_2];
    valeur_3:= Context.Items[clé_3];

Par conséquent:
   dans a_21_redirect_asp_net.pas, mettez entre commentaire la ligne Redirect et remplacez-la par celle avec Transfer:

procedure T_21_redirect_asp_net.Page_Load(senderSystem.Object
    eSystem.EventArgs);
  begin
    if IsPostBack
      then begin
          // Response.Redirect('a_21_bye.aspx?customer=' 
          //     + name_textbox.Text;

        Context.Items.Add('customer'name_textbox.Text);
        Server.Transfer('a_21_bye.aspx');
      end;
  end// Page_Load

   dans a_21_bye.pas, remplacez Request.QueryString par Context.Items :

procedure T_21_bye_form.Page_Load(senderSystem.Object
    eSystem.EventArgs);
  begin
    // Label1.Text:= 'Bye '+ Request.QueryString['customer'];
    Label1.Text:= System.String.Format('bye {0}'
        [Context.Items['customer']]);
  end// Page_Load

   compilez et exécutez. Tapez "Sam" et cliquez "send"
   voici la page retournée:

transfer asp net response



Notez aussi que:
  • outre Response, la page ancêtre de notre classe, tPage, possède une propriété Request qui nous permet de récupérer la plupart des paramètres concernant la requête envoyée par l'utilisateur
  • la propriété Context est extrêmement importante, car elle constitue la "colonne vertébrale" du traitement de la requête: toutes les informations provenant de l'utilisateur et celles retournant vers lui sont directement ou indirectement liées à Context. Dans notre exemple, Context nous a permis de communiquer entre deux pages



4.3 - Validation de saisie

Un autre élément très pratique est la présence de contrôles de validation de saisie. Pour vérifier que notre utilisateur tape effectivement un nom, nous utilisons un contrôle de validation:
  • nous plaçons le contrôle de validation sur la Forme
  • nous associons ce contrôle à une élément à vérifier (un champ vide, une valeur à tester ...) et fournissons un message d'erreur
  • lorsque l'erreur est détectée, le message est affiché
Testons, par exemple, que l'utilisateur a bien rempli son nom lorsqu'il soumet sa FORMe:
   sélectionnez l'onglet "design" de la page a_21_redirect_asp_net
   dans l'onglet des contrôles Web de la palette, sélectionnez RequiredFieldValidator:

asp net validator

Et

  • donnez à sa propriété ControlToValidate la valeur name_textbox
  • dans sa propriété ErrorMessage, placez un texte d'erreur. Par exemple

      Le nom est vide

   compilez et exécutez. Puis cliquez "send" SANS remplir la TextBox
   Cassini retourne une page où le message d'erreur est affiché:

asp net validator




5 - Asp.Net et Bases de Données

5.1 - Une ListBox affichant un tableau

Commençons par afficher dans une ListBox les données provenant d'un tableau:
  • nous remplissons un tableau avec des chaînes
  • nous relions ListBox.DataSource au tableau
  • nous appelons DataBind pour remplir la Listbox.
Voici le premier exemple:
   créez une nouvelle application Asp.Net, p_listbox_array_binding_2 et compilez
   posez une tListBox sur la Forme
   remplissez un tableau avec des valeur:
  • dans la zone PUBLIC de t_31_listbox_array_binding_form déclarez un tableau:

    m_arrayarray[1..5] of System.String;

  • dans t_31_listbox_array_binding_form.OnInit, remplissez le tableau et reliez ListBox1.DataSource à ce tableau :

    procedure t_31_listbox_array_binding_form.OnInit(eEventArgs);
      var l_indexInteger;
      begin
        InitializeComponent;
        inherited OnInit(e);

        m_array[1]:= 'asp_net';
        m_array[2]:= 'ado_net';
        m_array[3]:= 'delphi_2006';
        m_array[4]:= 'win32_to_.net';
        m_array[5]:= 'tcp_ip_sockets';

        ListBox1.DataSource:= m_array;
      end;


   posez un tButton sur la Forme, nommez-le "bind_button", créez son événement OnClick et appelez tPage.DataBind:

procedure t_31_listbox_array_binding_form.bind_button_Click(senderSystem.Object;
    eSystem.EventArgs);
  begin
    DataBind;
  end// bind_button_Click

   posez un tButton sur la Forme, appelez le "submit_button"

   pour visualiser l'élément de la ListBox sélectionnez,
  • posez un tLabel sur la Forme
  • créez l'événement ListBox1.SelectedIndexChanged et affichez l'index de l'item sélectionné:

    procedure t_31_listbox_array_binding_form.ListBox1_SelectedIndexChanged(senderSystem.Object;
        eSystem.EventArgs);
      begin
        Label1.Text:= 'selected index= 'ListBox1.SelectedIndex.ToString;
      end// ListBox1_SelectedIndexChanged

   compilez et exécutez
   Cassini envoie une page avec une ListBox vide:

asp net validator

   cliquez "do_bind"

   Cassini remplit la ListBox et renvoie la page:

asp net validator

   sélectionnez "tcp_ip_socket" et cliquez "send"

   Cassini renvoie l'index sélectionné:

asp net validator



Notez que:
  • nous avons effectué le chargement en plusieurs fois. En fait, il suffit d'initialiser le tableau et appeler DataBind une seule fois dans Page_Load, et seulement pour la première requête (IF NOT IsPostBack)
  • pour le bouton "submit", il n'y a pas besoin de créer un événement qui "enverrait" la requête vers Cassini: l'émission fait partie intégrante de la mécanique CGI .HTML: si une <FORM> contient un bouton, son click envoie une requête vers le Serveur


5.2 - ListBox et Tableau d'Objets

Nous avons utilisé un tableau de String. En fait, la tListBox se lie à n'importe quelle données qui implémente l'INTERFACE iList. Or un tableau implémente cette INTERFACE. Il faut un certain temps aux développeurs Delphi pour réaliser que, même si la syntaxe est celle de Pascal, nous travaillons en réalité en Java. Or en Java, un entier est un objet, un réel est un objet, un tableau est un objet. Un ARRAY OF est donc plus proche d'une tList que d'un paquet d'octets contenant les cellules en mémoire.

Notre tableau contenait des Strings (donc des Objets String). Mais nous pouvons placer dans les cellules d'autres données descendant de tObject. Pour cela, il faut:

  • que les cellules soient des Objets
  • que les champs soient des PROPERTYes PUBLIC
Nous avons donc créé une UNITé contenant une CLASSe c_training que voici:

unit u_c_training;
  interface

    type c_trainingclass
                       Public
                         m_idInteger;
                         m_titleSystem.String;
                         m_priceDouble;

                         Constructor create_training(p_idInteger;
                             p_titleSystem.Stringp_priceDouble);

                         property id : Integer read m_id write m_id;
                         property title : System.String read m_title write m_title;
                         property price : Double read m_price write m_price;
                       end// c_training

  implementation
    
    Constructor c_training.create_training(p_idInteger;
        p_titleSystem.Stringp_priceDouble);
      begin
        Inherited Create;

        m_id:= p_id;
        m_title:= p_title;
        m_price:= p_price;
      end// create_training

  end

Pour relier la tListBox:

  • nous affectons à tListBox.DataSource le tableau m_c_training_array
  • nous associons tListBox.DataTextField et la propriété "title" de chaque objet. DataTextField indique quel champ sera affiché
  • nous associons tListBox.DataValueField et la propriété "id" de chaque objet. DataValueField indique quel champ sera envoyé comme clé
Par conséquent:
   créez une nouvelle application Asp.Net, p_listbox_array_binding_3 et compilez
   tapez l'unité u_c_training présentée ci-dessus, et importez-la dans la liste des USES de p_listbox_array_binding_3
   posez une tListBox sur la Forme
   dans la zone PUBLIC de t_31_listbox_array_binding_form déclarez le tableau:

m_c_training_arrayarray of c_training;

   dans tForm.PageLoad remplissez le tableau et liez les données:

procedure t_31_listbox_array_binding_3.Page_Load(senderSystem.Object;
    eSystem.EventArgs);
  var l_training_indexInteger;

  procedure add_a_training(p_idIntegerp_customerSystem.Stringp_amountDouble);
    var l_c_trainingc_training;
    begin
      l_c_training:= c_training.create_training(p_idp_customerp_amount);

      m_c_training_array[l_training_index]:= l_c_training;
      Inc(l_training_index);
    end// add_a_training

  begin // Page_Load
    if not IsPostBack
      then begin
          SetLength(m_c_training_array, 5);

          l_training_index:= 0;
          add_a_training(201, 'Asp_net', 1400.00);
          add_a_training(202, 'ado_net', 1400.00);
          add_a_training(203, 'delphi_2006_net', 2400.00);
          add_a_training(204, 'win32_to_.net',1400.00);
          add_a_training(205, 'tcp_ip_sockets', 1400.00);

          Listbox1.DataSource:= m_c_training_array;
          ListBox1.DataTextField:= 'title';
          ListBox1.DataValueField:= 'id';
          DataBind;
        end;
  end// Page_Load

   posez un tButton sur la Forme, appelez le "submit_button"

   pour visualiser l'élément de la ListBox sélectionnez,
  • posez un tLabel sur la Forme
  • créez l'événement ListBox1.SelectedIndexChanged et affichez le contenu de l'item sélectionné

    procedure t_31_listbox_array_binding_3.ListBox1_SelectedIndexChanged(senderSystem.Object;
        eSystem.EventArgs);
      begin
        Label1.Text:= 'selected value: '
           + ListBox1.Items[ListBox1.SelectedIndex].ToString;
      end// ListBox1_SelectedIndexChanged

   compilez et exécutez
   Cassini envoie une page avec la ListBox remplie:

asp net validator

   sélectionnez "win32_to_.net" et cliquez "send"

   Cassini renvoie l'index sélectionné:

asp net validator



Voici le contenu des paquets échangés:
   le Client demande la page (le détail des en-têtes HTTP et le détail du _VIEWSTATE codé ont été en partie supprimés ou abrégés)

 
    -> | GET /p_31_listbox_array_binding_3/a_31_listbox_array_binding_3.aspx HTTP/1.1

   Cassini renvoie la page

 
 <-    | HTTP/1.1 200 OK
...
 <-    | <html>
 <-    |   <body>
 <-    | <input type="hidden" name="__VIEWSTATE" value="dDwtNTY ...VmDK4=" />
 <-    |       <select name="ListBox1" size="4" id="ListBox1" style="height:132px;width:105px;">
 <-    |         <option value="201">Asp_net</option>
 <-    |         <option value="202">ado_net</option>
 <-    |         <option value="203">delphi_2006_net</option>
 <-    |         <option value="204">win32_to_.net</option>
 <-    |         <option value="205">tcp_ip_sockets</option>
 <-    |       </select>
 <-    |       <input type="submit" name="submit_button" value="send" id="submit_button" />
 <-    |       <span id="Label1">Label</span>
 <-    |      </form>
 <-    |   </body>
 <-    | </html>
 <-    | 

   l'utilisateur sélectionne "win32_to_.net" et clique "send"

 
    -> | POST /p_31_listbox_array_binding_3/ a_31_listbox_array_binding_3.aspx HTTP/1.1
...
    -> | __VIEWSTATE=dDwtN...AWsVmDK4%3D&ListBox1=204&submit_button=send

   Cassini renvoie la valeur du Label

 
 <-    | HTTP/1.1 200 OK
...
 <-    | <input type="hidden" name="__VIEWSTATE" value="dDwtNTY ... JkfbgA==" />
 <-    |       <select name="ListBox1" size="4" id="ListBox1" style="height:132px;width:105px;">
 <-    |         <option value="201">Asp_net</option>
 <-    |         <option value="202">ado_net</option>
 <-    |         <option value="203">delphi_2006_net</option>
 <-    |         <option selected="selected" value="204">win32_to_.net</option>
 <-    |         <option value="205">tcp_ip_sockets</option>
 <-    | 
 <-    |       </select>
 <-    |       <input type="submit" name="submit_button" value="send" id="submit_button" />
 <-    |       <span id="Label1">selected value: win32_to_.net</span>
 <-    |      </form>
 <-    |   </body>
 <-    | </html>



Et:
  • nous ne chargeons la ListBox que lors de la première requête. En effet le retour de Cassini montre bien les champs .HTML de type SELECT dûment remplis
  • lorsque nous soumettons la <FORM> la mécanique CGI ajoute bien l'élément sélectionné et "qui" a cliqué:

     
    ... &ListBox1=204&submit_button=send

  • le contenu de la ListBox ne sont pas transmis dans les balises SELECT. Or nous ne reconstruisons pas la ListBox dans Page_Load. Et pourtant au retour de la soumission, nous avons bien nos champs.

  • Eh bien c'est le Viewstate de la soumission qui avait codé ces champs.

    Voici le viewstate de-uuencodé:

     
    t<-566616781;t<;l<i<1>;>;l<t<;l<i<1>;i<5>;>;l<t<t<p<p
    <l<DataTextField;DataValueField;>;l<title;id;>>;>;t<
    i<5>;@<Asp_net;ado_net;delphi_2006_net;win32_to_.net;tcp_ip_sockets;>;
    @<201;202;203;204;205;>>;l<i<3>;>>;;>;t<p<p<l<Text;>;
    l<selected value: win32_to_.net;>>;>;;>;>>;>>;>û3m8@©ú"~ÀS2=éÐL&GÛ€

    et voici son contenu débarrassé de sa gangue pseudo-XML fourni par le viewer de Viewstate :

     
    tree_hash -566616781
       control 1
        [1] Asp_net=201, ado_net=202, delphi_2006_net=203, win32_to_.net=204, tcp_ip_sockets=205,
          3
        [5] Text=selected value: win32_to_.net,



5.3 - ListBox et Base de Données

Maintenant que nous savons afficher des données dans une tListBox, l'étape suivante est de peupler la tListBox depuis une base de données.

Pour cela, il suffit de remplir un tDataTable à partir d'une base de données, puis de lier:

  • tListBox.DataSource et tDataTable.DefaultView
  • tListBox.DataTextField et la colonne à afficher
  • tListBox.DataValueField et la colonne de référence (code)
Nous remplirons la tDataTable en utilisant du code Ado.Net standard:
  • BdpConnection ouvrira la connexion
  • BdpDataAdapter
    • contiendra la commande SELECT
    • remplira un tDataSet par l'appel tDataAdapter.Fill(tDataSet, nom_table)
Ces explications sont plus que succintes. Nous pourrions faire un tutorial Ado.Net ici, mais la dernière fois que nous avons présenté un tutorial, il y en a eu pour 268 K. Nous nous permettrons donc de suggérer au lecteur intéressé par l'architecture Ado.Net à consulter ce Tutorial Ado.Net.

Nous utiliserons pour notre exemple le serveur Interbase, livré par défaut avec Delphi. Nous allons commencer pour ce premier exemple par récupérer les données du serveur en code pur. Les étapes de connexion, chargement et liaison seront ainsi clairement identifiées.

Voici donc notre exemple:
   créez une nouvelle application Asp.Net, p_listbox_database_binding_2 et compilez
   créez un répertoire

  c:\programs\fr\asp_net\tutorial\_data\

et copiez-y le fichier EMPLOYEE.GDB, figurant, normalement en

  C:\Program Files\Fichiers communs\Borland Shared\Data\

Cela nous permettra de modifier les tables sans état d'âme

   posez une tListBox sur la Forme

   posez un tButton sur la Forme, appelez le "submit_button". Créez son événement OnClick et chargez les données de la table DEPARTMENT dans Listbox1:

const k_database_path'C:\Programs\fr\asp_net\tutorial\_data\';
      k_database_full_file_namek_database_path'employee.gdb';
      k_user_password'Username=SYSDBA;Password=masterkey';

      k_assembly'assembly=Borland.Data.Interbase, Version=2.5.0.0, '
          + 'Culture=neutral, PublicKeyToken=91d62ebb5b0d1b1b';
      k_vendor_client'vendorclient=gds32.dll';
      k_provider'provider=Interbase';

      k_connection_string=
          'Database='k_database_full_file_name
          + ';'k_user_password
          + ';'k_assembly
          + ';'k_vendor_client
          + ';'k_provider
          ;

      k_select'Select * from department';

procedure t_32_listbox_databinding_2.submit_button_Click(senderSystem.Object;
    eSystem.EventArgs);
  var l_c_connectionBdpConnection;
      l_c_data_adapterBdpDataAdapter;
      l_c_data_setDataSet;
      l_c_data_tableDataTable;
  begin
    l_c_connection:=  BdpConnection.Create(k_connection_string);
    l_c_data_adapter:= BdpDataAdapter.Create(k_selectl_c_connection);
    l_c_data_set:= DataSet.Create();
    l_c_data_adapter.Fill(l_c_data_set'department');
    l_c_data_table:= l_c_data_set.Tables['department'];

    l_c_connection.Open();

    ListBox1.DataSource:= l_c_data_table.DefaultView;
    ListBox1.DataTextField:= 'Location';
    ListBox1.DataValueField:= 'Dept_No';

    DataBind;

    l_c_connection.Close();
  end// submit_button_Click

   compilez et exécutez
   Cassini envoie une page avec la ListBox vide:
   cliquez "send"

   Cassini charge la Listbox et renvoie la page:

asp net validator



Notez que

  • comme pour le chargement de la Listbox à partir d'un tableau, le chargement à partir d'une table se fait une seule fois. Il n'y a pas de liaison permanente avec la base de données. En effet, la page part à l'autre bout du monde, et une requête de soumission ne viendra peut être jamais
    C'est pourquoi nous pouvons ouvrir la connexion juste avant le chargement, et la refermer juste après ce chargement.
  • notez aussi que pour les stages j'ai eu la désagréable surprise de voir que des applications développées sur une machine ne fonctionnaient pas sur un autre poste ayant une version différente des composants de bases de données. Pour cette présentation, nous avions commencé les exemples en Delphi 2005, puis comme nous avons actuellement Delphi 2006, nous avons utilisé cette nouvelle version pour le tutorial. Ici aussi, Asp.Net ne fut pas toujours d'accord.
    Pour ces exemples simples, la solution fut simplement de recréer un exemple "bis". Un solution moins radicale consiste à effacer tous les .DCUIL, et, dans le cas des base de données, de bien vérifier les chaînes de connexion. Dans certains cas j'ai aussi effacé la référence à l'Assembly de données Borland dans le .DPR:
    • Delphi 2005 référence
        {%DelphiDotNetAssemblyCompiler
          'c:\program files\fichiers communs\borland shared\bds\shared
           assemblies\3.0\Borland.Data.Provider.dll'}
    • le BDS de 2006 a un numéro d'assembly 4.0
  • dans l'exemple actuel, nous avons récupéré la chaîne de connexion en tirant-glissant une BdpConnection provenant du DataExplorer sur la Forme. Vous retrouverez d'ailleurs cette BdpConnection1 dans le .ZIP des sources


5.4 - Repeater

Asp.Net propose toute une série de composants capables de formatter des lignes de données avec
  • en-tête de liste
  • lignes répétitives
  • pied de liste
Ayant vu comment était traité la Listbox, il n'y a trop rien de surprenant à généraliser cette technique de mise en forme de lignes de données

Le principe de ces composants est la suivante:

  • fournit les données. Dans notre cas, nous les utiliserons depuis la table DEPARTMENT
  • l'essentiel du code consiste à définir l'en-tête, la répétition, et le pied de table. Et cela se fait au niveau du texte .ASPX (pas les controles et le code .PAS)
Voici le projet:
   créez une nouvelle application Asp.Net, p_33_repeater et compilez
   vérifiez (ou créez et copier) que EMPLOYEE.GDB est bien dans

  c:\programs\fr\asp_net\tutorial\_data\

   créez une nouvelle connexion dans l'Explorateur de base de données:
  • dans la partie supérieure gauche, sélectionnez l'onglet "DataExplorer"

    asp net validator

  • effectuez un click droit souris sur "Interbase" et sélectionnez "Add New Connection"

  • dans le dialogue de nouvelle connexion, tapez le nom de la nouvelle connexion, par exemple "asp_tutorial"

    asp net validator

  • dans l'explorateur, sur "Interbase | asp_tutorial", cliquez le bouton droit et sélectionnez "modify connection"

  • dans l'éditeur de connexion, initialisez le chemin de EMPLOYEE.GDB, le nom d'utilisateur et le mot de passe

    asp net validator

  • cliquez "test" pour vérifier la connexion et fermez
   dans le DataExplorer, sélectionnez la connexion "asp_tutorial" et tirez la sur la Forme
   Delphi pose un BdpConnection1 dans la zone des composants non-visuels
   à titre de vérification, effectuez un clic droit souris sur BdpConnection1, sélectionnez "connection editor" et cliquez "test" pour vérifier que la connexion est correcte

   posez un repeater sur la Forme

asp net validator

   posez un tButton sur la Forme, créez son événement OnClick, et faites-lui remplir Repeater1:

procedure T_33_repeater_form.submit_button_Click(senderSystem.Object;
    eSystem.EventArgs);
  var l_c_data_adapterBdpDataAdapter;
      l_c_data_setDataSet;
      l_c_data_tableDataTable;
  begin
    l_c_data_adapter:= BdpDataAdapter.Create(k_selectBdpConnection1);
    l_c_data_set:= DataSet.Create();
    l_c_data_adapter.Fill(l_c_data_set'department');
    l_c_data_table:= l_c_data_set.Tables['department'];

    BdpConnection1.Open();

    Repeater1.DataSource:= l_c_data_table.DefaultView;
    DataBind;

    BdpConnection1.Close();
  end// submit_button_Click

   à présent définissez le format des données à afficher dans le fichier .ASPX:

 
<%@ Page Language="c#" Debug="true"
    Codebehind="a_33_repeater.pas" AutoEventWireup="false"
    Inherits="a_33_repeater.T_33_repeater_form"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title></title>
  </head>
  <body ms_positioning="GridLayout">
    <form runat="server">
      <asp:Button id="submit_button"
          style="Z-INDEX: 1; LEFT: 350px; POSITION: absolute; TOP: 38px"
          runat="server" text="send"></asp:Button>
      <asp:Repeater id="Repeater1" runat="server">
        <HeaderTemplate>
        <table>
          <tr>
            <td bgcolor=#B0B0FF>ID</td>
            <td bgcolor=#B0B0FF>Département</td>
            <td bgcolor=#B0B0FF>Ville</td>
          </tr>
        </HeaderTemplate>
           <ItemTemplate>
             <tr>
               <td><%#((System.Data.DataRowView)Container.DataItem)["dept_no"]%>
               </td>
               <td><%#DataBinder.Eval(Container.DataItem, "department")%>
               </td>
               <td><%#DataBinder.Eval(Container.DataItem, "location")%>
               </td>
             </tr>
           </ItemTemplate>
         <FooterTemplate>
         </table>
         </FooterTemplate>
       </asp:Repeater>
     </form>
  </body>
</html>

   compilez et exécutez
   Cassini envoie une page avec juste le bouton "send"
   cliquez "send"

   Cassini charge le repeater (partiel):

asp net validator

dont le contenu .HTML est le suivant:

 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title></title>
  </head>
  <body ms_positioning="GridLayout">
    <form name="_ctl0" method="post" action="a_33_repeater.aspx" id="_ctl0">
      <input type="hidden" name="__VIEWSTATE" value="dDw ... Cn0A==" />
      <input type="submit" name="submit_button" value="send" id="submit_button" style="Z-INDEX: 1; LEFT: 350px; POSITION: absolute; TOP: 38px" />
      <table>
        <tr>
          <td bgcolor="#B0B0FF">ID</td>
          <td bgcolor="#B0B0FF">Département</td>
          <td bgcolor="#B0B0FF">Ville</td>
        </tr>
        <tr>
          <td>000</td>
          <td>Corporate Headquarters</td>
          <td>Monterey</td>
        </tr>
        <tr>
          <td>100</td>
          <td>Sales and Marketing</td>
          <td>San Francisco</td>
        </tr>
        ...
      </table>
    </form>
  </body>
</html>



Comme on pouvait s'en douter, les lignes ajoutées dans le fichier .ASPX servent de modèle pour la page .HTML



5.5 - DataGrid en Lecture

Le composant royal de traitement de données est la grille. En terme Asp.Net il s'agit d'un tDataGrid.

Et le DataGrid est simplement connecté par sa propriété DataSource à tDataTable.DefaultView

Voici notre premier exemple:
   créez une nouvelle application Asp.Net, p_34_datagrid_select et compilez
   vérifiez ou créés la connexion asp_tutorial (voir ci-dessus)

   posez une tDataGrid sur la Forme

asp net validator

   dans le DataExplorer, sélectionnez la connexion "asp_tutorial" et tirez la sur la Forme
   Delphi pose un BdpConnection1 dans la zone des composants non-visuels
   à titre de vérification, effectuez un clic droit souris sur BdpConnection1, sélectionnez "connection editor" et cliquez "test" pour vérifier que la connexion est correcte

   posez un tButton sur la Forme, créez son événement OnClick, et faites-lui remplir la DataGrid:

const k_select'Select * from department';

procedure T_34_datagrid_select_form.submit_button_Click(senderSystem.Object;
    eSystem.EventArgs);
  var l_c_data_adapterBdpDataAdapter;
      l_c_data_setDataSet;
      l_c_data_tableDataTable;
  begin
    l_c_data_adapter:= BdpDataAdapter.Create(k_selectBdpConnection1);
    l_c_data_set:= DataSet.Create();
    l_c_data_adapter.Fill(l_c_data_set'department');
    l_c_data_table:= l_c_data_set.Tables['department'];

    BdpConnection1.Open();
    DataGrid1.DataSource:= l_c_data_table.DefaultView;
    DataBind;
    BdpConnection1.Close();
  end// submit_button_Click

   compilez et exécutez
   Cassini envoie une page avec juste le bouton "send"
   cliquez "send"

   Cassini charge la DataGrid:

asp net validator



Fort simple, n'est-ce pas. Hélas, simplicité trompeuse. La dbGrid était déjà un sujet de légitime fierté de Delphi 1 par rapport aux tableaux de tEdit du Visual Basic. Eh bien la DataGrid HTML Asp.Net a encore plus de possibilités, de propriétés, d'options. Elle remplirait des livres entiers. Nous n'en sommes pas là, et nous contenterons de fournir deux autres exemples de son utilisation.



5.6 - Pagination

Comme vous pouvez le constater, la page .HTML ci-dessus affiche TOUTE les lignes.

Nous pouvons afficher page à page en bridant le nombre de lignes affichées par page, et en mettant en place une mécanique d'appel des pages suivantes (ou précédentes). En fait, Asp.Net fait tout le travail pour nous.

Pour paginer, nous devons

  • remplir la page comme précédemment
  • dans l'ébauche .ASPX, brider le nombre de lignes de la DataGrid par un attribut "pagesize"
  • dans le code .PAS répondre à l'événement tDataGrid.PageIndexChanged en retournant à Cassini le nouvel index de début de page
Voici le projet:
   créez une nouvelle application Asp.Net, p_35_datagrid_page et compilez
   vérifiez ou créés la connexion asp_tutorial (voir ci-dessus)

   dans le DataExplorer, sélectionnez la connexion "asp_tutorial" et tirez la sur la Forme
   Delphi pose un BdpConnection1 dans la zone des composants non-visuels

   posez une tDataGrid sur la Forme

   dans la partie PUBLIC de T_35_datagrid_page déclarez une méthode qui remplira les lignes de DataGrid1.

T_35_datagrid_page = class(System.Web.UI.Page)
                       ...
                       public
                         procedure fetch_data;
                     end// T_35_datagrid_page

et écrivez le code qui remplit la grille (similaire aux méthodes précédentes):

const k_select'Select dept_no, department, location from department';

procedure T_35_datagrid_page.fetch_data;
  var l_c_data_adapterBdpDataAdapter;
      l_c_data_setDataSet;
      l_c_data_tableDataTable;
  begin
    l_c_data_adapter:= BdpDataAdapter.Create(k_selectBdpConnection1);
    l_c_data_set:= DataSet.Create();
    l_c_data_adapter.Fill(l_c_data_set'department');
    l_c_data_table:= l_c_data_set.Tables['department'];

    BdpConnection1.Open();

    DataGrid1.DataSource:= l_c_data_table.DefaultView;
    DataBind;
    BdpConnection1.Close();
  end// fetch_data

   sélectionnez DataGrid1, créez son événement PageIndexChanged:

procedure T_35_datagrid_page.DataGrid1_PageIndexChanged(sourceSystem.Object;
    eSystem.Web.UI.WebControls.DataGridPageChangedEventArgs);
  begin
    DataGrid1.CurrentPageIndex:= e.NewPageIndex;
    fetch_data;
  end// DataGrid1_PageIndexChanged

   dans le fichier .ASPX (ou dans la zone d'édition .HTML située sous la Forme), bridez le nombre de lignes à 4:

 
<html>
  <head>
    <title></title>
  </head>
  <body ms_positioning="GridLayout">
    <form runat="server">
      <asp:DataGrid id="DataGrid1"
         style="Z-INDEX: 1; LEFT: 22px; POSITION: absolute; TOP: 14px"
         runat="server" allowpaging="True"
         pagesize="4">
      </asp:DataGrid>
    </form>
  </body>
</html>

   compilez et exécutez
   Cassini affiche la première page de 4 lignes de la table
   en dessous de la grille, cliquez ">"
   Cassini affiche les 4 lignes suivantes:

asp net validator



La position courante est gérée dans des champs cachés calculés en utilisant JavaScript (parce que nous avons autorisé JavaScript sur Internet Explorer). Voici ce que Cassini a renvoyé en réponse à la première requête:

 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title></title>
  </head>
  <body ms_positioning="GridLayout">
    <form name="_ctl0" method="post" action="a_35_datagrid_page.aspx" id="_ctl0">
      <input type="hidden" name="__EVENTTARGET" value="" />
      <input type="hidden" name="__EVENTARGUMENT" value="" />
      <input type="hidden" name="__VIEWSTATE" value="dDw2ODM5M...4zShk=" />
      <script language="javascript" type="text/javascript">
      <!--
        function __doPostBack(eventTarget, eventArgument)
          {
            var theform;
            if (window.navigator.appName.toLowerCase().indexOf("microsoft") > -1)
              {
                theform = document._ctl0;
              }
            else
              {
                theform = document.forms["_ctl0"];
              }
            theform.__EVENTTARGET.value = eventTarget.split("$").join(":");
            theform.__EVENTARGUMENT.value = eventArgument;
            theform.submit();
           }
      // -->
      </script>
      <table cellspacing="0" rules="all" border="1" id="DataGrid1" style="border-collapse:collapse;Z-INDEX: 1; LEFT: 22px; POSITION: absolute; TOP: 14px">
        <tr>
          <td>DEPT_NO</td><td>DEPARTMENT</td><td>LOCATION</td>
        </tr>
        <tr>
          <td>000</td><td>Corporate Headquarters</td><td>Monterey</td>
        </tr>
        <tr>
          <td>100</td><td>Sales and Marketing</td><td>San Francisco</td>
        </tr>
        <tr>
          <td>600</td><td>Engineering</td><td>Monterey</td>
        </tr>
        <tr>
          <td>900</td><td>Finance</td><td>Monterey</td>
        </tr>
        <tr>
          <td colspan="3">
            <span><</span> 
            <a href="javascript:__doPostBack('DataGrid1$_ctl8$_ctl1','')">></a>
          </td>
        </tr>
      </table>
    </form>
  </body>
</html>

En gros:

  • le clic sur ">" (7ième ligne avant la fin) appelle la fonction Javascript doPostBack
  • cette fonction va utiliser les champs __EVENTTARGET et __EVENTTARGUMENT pour renvoyer à Cassini les paramètres du nouveau paquet de lignes


5.7 - Modification de Données

Nous pouvons aussi modifier les données présentées dans une Datagrid.

Dans les exemples précédents, les données de la tDataTable Ado.Net étaient présentées sous forme de texte dans une <TABLE> .HTML. Ces données sont donc en lecture pure.

Pour pouvoir laisser l'utilisateur taper du texte, il faut obligatoirement passer par des Edit .HTML et envoyer le texte tapé par l'utilisateur vers le Serveur. C'est ce que nous avons présenté dans l'article Gestion Base de Données CGI. Dans les programmes qui permettaient la modification de données d'une Table Interbase

  • notre page .HTML contenait des Edit .HTML
  • un bouton "UPDATE" envoyait le contenu des ces Edit sous forme de paramètres CGI
  • le programme CGI récupérait ces paramètres pour mettre à jour la base en utilisant une requête SQL UPDATE
Eh bien, en Asp.Net c'est exactement la même chose, sauf que nous n'avons pas besoin de générer la page avec les Edit. De façon plus détaillée:
  • nous ajoutons une tDataGrid à la Forme
  • nous ajoutons une colonne spéciale qui permettra de récupérer une ligne avec des Edit
  • l'utilisateur modifie les valeurs des Edit
  • lorsque la page est soumise au Serveur, le code .PAS récupérera les données modifiées, et se chargera de mettre à jour la Table Interbase
Comme cette mécanique est un peu inhabituelle, nous allons d'abord présenter le résultat, et ensuite le code. Voici donc les étapes, vu côté utilisateur:
   l'utilisateur demande la page
   Cassini renvoie une page, avec la DataGrid dans laquelle une colonne contient un lien "edit":

asp
net validator

   l'utilisateur décide de changer "San Francisco" en "Los Angeles". Il clique le lien "Edit"

   Cassini lui renvoie une nouvelle page où les champs de la ligne "San Francisco" ont été placés dans des Edit, et "Edit" a été remplacé par "Update / Cancel".

asp net validator
-at_53_datagrid_edit_answer_2

   L'utilisateur modifie les valeurs dans les boîtes d'édition. Dans notre cas il tape "Los Angeles":

asp net validator

Puis il soumet la mise à jour en cliquant "Update"

   la modification est soumise à Cassini, qui met à jour la Table SQL et renvoie les données modifiées:

asp net validator



En résumé, le mécanisme est identique à notre code CGI manuel, sauf que c'est Asp.Net qui a placé des liens "edit" ou "update cancel" dans une colonne spéciale de la tDataGrid.



Voici donc comment code cet exemple:
   créez une nouvelle application Asp.Net, p_36_datagrid_edit_2 et compilez
   vérifiez ou créés la connexion asp_tutorial (voir ci-dessus)

   dans le DataExplorer, sélectionnez la connexion "asp_tutorial" et tirez la sur la Forme
   Delphi pose un BdpConnection1 dans la zone des composants non-visuels

   posez une tDataGrid sur la Forme

   dans la partie PUBLIC de T_35_datagrid_page déclarez une méthode qui remplira les lignes de DataGrid1.

T_36_datagrid_edit_2_form = class(System.Web.UI.Page)
                              ...
                              public
                                procedure select_data;
                            end// T_36_datagrid_edit_2_form

et écrivez le code qui remplit la grille (similaire aux méthodes précédentes):

const k_select'Select dept_no, department, location from department';

procedure T_36_datagrid_edit_2_form.select_data;
  var l_c_data_adapterBdpDataAdapter;
      l_c_data_setDataSet;
      l_c_data_tableDataTable;
  begin
    l_c_data_adapter:= BdpDataAdapter.Create(k_selectBdpConnection1);
    l_c_data_set:= DataSet.Create();
    l_c_data_adapter.Fill(l_c_data_set'department');
    l_c_data_table:= l_c_data_set.Tables['department'];

    DataGrid1.DataKeyField:= 'dept_no';
    DataGrid1.DataSource:= l_c_data_table.DefaultView;

    BdpConnection1.Open();
    DataBind;
    BdpConnection1.Close();
  end// select_data

   dans l'événement tPage.Page_Load, chargez la table:

procedure T_36_datagrid_edit_2_form.Page_Load(senderSystem.Object;
    eSystem.EventArgs);
  begin
    if not IsPostBack
      then select_data;
  end// Page_Load

   sélectionnez DataGrid1.

Dans le fichier .ASPX (ou dans la zone d'édition .HTML située sous la Forme), ajoutez au milieu de <ASP:Datagrid> </ASP:Datagrid> ajoutez la balise qui permettra la génération de la colonne "edit / update / cancel" (tout et y compris <Column> ... </Column>):

 
<%@ Page language="c#" Debug="true"
    Codebehind="a_36_datagrid_edit_2.pas" AutoEventWireup="false"
    Inherits="a_36_datagrid_edit_2.T_36_datagrid_edit_2_form" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title></title>
  </head>
  <body ms_positioning="GridLayout" style="WIDTH: 653px; HEIGHT: 271px">
    <form runat="server">
      <ASP:DataGrid id="DataGrid1" style="Z-INDEX: 3; LEFT: 14px; POSITION: absolute; TOP: 14px" runat="server">
        <Columns>
          <asp:EditCommandColumn edittext="Edit1" updatetext="Update" canceltext="Cancel"
            headertext="Edit">
          </asp:EditCommandColumn>
        </Columns>
      </ASP:DataGrid>
    </form>
  </body>
</html>

   A présent les événements. Sélectionnez DataGrid1, créez son événement EditCommand:

procedure T_36_datagrid_edit_2_form.DataGrid1_EditCommand(sourceSystem.Object
    eSystem.Web.UI.WebControls.DataGridCommandEventArgs);
  begin
    DataGrid1.EditItemIndex:= e.Item.ItemIndex;
    select_data;
  end// DataGrid1_EditCommand

et son événement CancelCommand:

procedure T_36_datagrid_edit_2_form.DataGrid1_CancelCommand(sourceSystem.Object
    eSystem.Web.UI.WebControls.DataGridCommandEventArgs);
  begin
    DataGrid1.EditItemIndex:= -1;
    select_data;
  end// DataGrid1_CancelCommand

finalement, updateCommand:

procedure T_36_datagrid_edit_2_form.DataGrid1_UpdateCommand(sourceSystem.Object;
    eSystem.Web.UI.WebControls.DataGridCommandEventArgs);
  var l_c_id_text_boxl_c_location_text_boxTextbox;
      l_update_requestString;
      l_c_commandBdpCommand;
      l_countInteger;
  begin
    select_data;

    l_c_id_text_box:= e.Item.Cells[1].Controls[0] as TextBox;
    l_c_location_text_box:= e.Item.Cells[3].Controls[0] as TextBox;

    l_update_request:= 'UPDATE department '
          + '  SET location ='''l_c_location_text_box.Text''''
          + '  WHERE dept_no= 'l_c_id_text_box.Text;

    l_c_command:= BdpCommand.Create(l_update_requestBdpConnection1);
    BdpConnection1.Open;
    l_count:= l_c_command.ExecuteNonQuery();
    BdpConnection1.Close;

    DataGrid1.EditItemIndex:= -1;
    DataGrid1.DataBind;
  end// DataGrid1_UpdateCommand

   compilez et exécutez


Notez que:

  • cet exemple est très intéressant. D'abord parce qu'il est très décevant. Pour quelqu'un habitué de taper à sa guise dans un dbGrid Delphi 6, voici qu'il faut demander la permission en cliquant le lien "edit". Cela surprend
  • pouvons nous faire mieux ? Bien sûr: en codant tout nous mêmes:
    • soit nous présentons une <TABLE> .HTML ne contenant que de Edit
    • soit nous détectons la frappe clavier et changeons dynamiquement l'affichage textuel en affichage dans un Edit, grâce à des scripts JavaScript
    Dans les deux cas, il faut envoyer le résultat vers le Serveur, et cela nécessite un clic sur un bouton de soumission (ou sur un lien "update")

  • Cela souligne une fois de plus que, quelle que soit la prestidigitation Asp.Net, la mécanique ne peut pas faire plus que l'antique .HTML ne le permet. Pour taper des données, il y a seulement des Edit. Un point c'est tout

  • est-ce grave docteur ? Pas réellement. Le but essentiel des applications Web n'est pas de taper des données dans des dbGrid:
    • soit nous gérons le contenu affiché dans une table, et donc il s'agit uniquement de lire des données
    • pour la saisie, la plupart du temps il s'agit de saisie "fiche à fiche". Prenez le cas typique d'une commande Amazon: on vous demande de cliquer ici ou là pour sélectionner les livres, puis à la fin vous tapez adresse, carte bancaire etc dans des Edits isolés
  • mentionnons aussi que la mécanique Asp.Net ne prévoit pas l'insertion d'une nouvelle ligne. C'est à nous de coder cette insertion manuellement



6 - Améliorations

6.1 - Qu'avons nous appris ?

Asp.Net est gigantesque. Nous avons tenu à présenter quelques exemples non triviaux pour vous permettre de goûter la chose. Quelques points semblent ressortir:
  • pour gérer des applications Asp.Net, il vaut mieux être familier avec les librairies du Framework .Net. Ici, point de tList, tStringList, IntToStr. Mais des tCollections, des ToString, des tStreamReader etc.
  • nous avons présenté les exemples "à marche forcée": pour remplir chaque objectif, nous avons indiqué comment faire. Point de détail sur toutes les possibilités ou alternatives, point de copie des innombrables tables de propriétés de l'aide Asp.Net. Une fois de plus notre objectif était de vous faire parcourir le plus de terrain possible pour prendre la mesure de ce nouveau domaine.
    L'autre conséquence est qu'il vous faudra vite devenir un expert dans la manipulation de l'aide Asp.Net. C'est là que vous trouverez les descriptions exhaustives et les syntaxes. Passez donc une heure ou deux à cliquer ici, synchroniser là le contenu avec l'arborescence (l'icône <-> tout en haut), basculer de l'index au contenu etc. C'est là un investisement que vous ne regretterez pas. Et finalement, ce n'est pas compliqué du tout: "Microsoft .Net Frameword | Reference | Class Library" et là vous êtes "in business" : System, System.Data, System.IO, System.Runtime.Remoting, System.Windows.Forms.
  • en finale, Asp.Net ne fait que générer du code .HMTL. Du .HTML pur et dur. Donc il est préférable de comprendre la syntaxe .HTML, et encore mieux d'avoir un peu pratiqué CGI ou ISAPI. Voyez nos tutoriaux dans ce domaine.


6.2 - Ce qui n'a pas été présenté

Asp.Net remplit des livres entiers. Forcémement nous n'avons pas pu tout aborder. En particulier:
  • la sécurité: la gestion des authentification et autorisation
  • l'optimisation et les caches
  • la configuration
  • plus généralement une présentation détaillée des CLASSes et des événements mis en oe
    uvre. En gros une analyse UML de la mécanique.


6.3 - Les Formations

Comme disait Alfred Hitchcock dans ses séries policières, "et voici un mot de notre sponsor". Nous animons donc tous les mois des Formation, avec tout particulièrement celles qui pourraient intéresser un développeur Asp.Net:
  • Formation Asp.Net consacrée aux compétences à acquérir pour réaliser des applications Asp.Net
  • formation Delphi 2005 / 2006 : une formation plus générale, qui couvre la librairie .Net, Ado Net et Asp.Net. Elle concerne surtout les personnes désireuses de passer du monde Win32 au monde .Net, en insistant sur les deux points clé: les bases de données et la programmation Internet
Nous intervenons aussi en tant que développeur Delphi, soit pour effectuer des transferts de technologie, réaliser des projets complets, ou appuyer des équipes sur des projets spécifiques.




7 - Télécharger le code source Delphi

Vous pouvez télécharger:

Ce .ZIP qui comprend:

  • les fichiers .ASPX / .PAS, les pages et unités annexes eventuelles
  • les fichiers de paramètres (le schéma et le batch de création)
  • dans chaque .ZIP, toutes les librairies nécessaires à chaque projet (chaque .ZIP est autonaume)
Ces .ZIP ne modifient pas votre PC (pas de changement de la Base de Registre, de DLL ou autre). Pour supprimer le projet, effacez le répertoire.

Notez que les chemins sont des chemins ABSOLUS. Pour ces applications, le chemin de base est:
  C:\programs\fr\asp_net\tutorial\

Et pour utiliser ces exemples:

  • créez ce répertoire
  • dézipez chaque example dans son sous-répertoire
  • compilez et exécutez


Comme d'habitude:
  • nous vous remercions de nous signaler toute erreur, inexactitude ou problème de téléchargement en envoyant un e-mail à jcolibri@jcolibri.com. Les corrections qui en résulteront pourront aider les prochains lecteurs
  • tous vos commentaires, remarques, questions, critiques, suggestion d'article, ou mentions d'autres sources sur le même sujet seront de même les bienvenus à jcolibri@jcolibri.com.
  • plus simplement, vous pouvez taper (anonymement ou en fournissant votre e-mail pour une réponse) vos commentaires ci-dessus et nous les envoyer en cliquant "envoyer" :
    Nom :
    E-mail :
    Commentaires * :
     

  • et si vous avez apprécié cet article, faites connaître notre site, ajoutez un lien dans vos listes de liens ou citez-nous dans vos blogs ou réponses sur les messageries. C'est très simple: plus nous aurons de visiteurs et de références Google, plus nous écrirons d'articles.



8 - Référénces

Google vous fournira de nombreux liens pour des tutoriaux Asp.Net.

Pour ma part, j'ai surtout consulté le livre de

  • Xavier PACHECO
        Delphi for .NET - Developper's Guide
          Sams - ISBN 0 672 32443 - 1 - 2004 - 2004
    • Ecrit pour Delphi 8, ce livre a le mérite de nous parler surtout du Framework .Net (Ado.Net et Asp.Net), en évitant de nous expliquer le détail de BEGIN et END. Il reste, même pour Delphi 2006, un ouvrage que je recommande chaudement.
Tout l'inverse de livres Français que j'ai feuilletés à l'occasion. "Lu et Approuvé par Borland France". Pardi, j'ai regardé. Un fratras de copies des aides Delphi, de figures Microsoft, et, pour le chapitre sur ECO, carrément la copie francisée d'un "White Paper" gratuit de Borland US d'Anthony RICHARDSON (Google: WhitePaperECOFirstApplication.pdf), plagié ici sans même citer l'auteur. Très très élégant. Le tout dans un style ampoulé qui fait franchement rigoler:
    "c'est Ado.Net tel un Neptune qui règne en maître sur tous les flots de données".
Et dire que l'intéressé passe son temps à parler de "professionnalisme". Etre sérieux et se prendre au sérieux sont deux choses très différentes, et nul doute que le lecteur a depuis longtemps fait la différence entre un Colibri facétieux et un Merlan prétentieux.




9 - L'auteur

John COLIBRI est passionné par le développement Delphi et les applications de Bases de Données. Il a écrit de nombreux livres et articles, et partage son temps entre le développement de projets (nouveaux projets, maintenance, audit, migration BDE, migration Xe_n, refactoring) pour ses clients, le conseil (composants, architecture, test) et la formation. Son site contient des articles avec code source, ainsi que le programme et le calendrier des stages de formation Delphi, base de données, programmation objet, Services Web, Tcp/Ip et UML qu'il anime personellement tous les mois, à Paris, en province ou sur site client.
Créé: sep-05. Maj: aou-15  148 articles, 471 sources .ZIP, 2.021 figures
Contact : John COLIBRI - Tel: 01.42.83.69.36 / 06.87.88.23.91 - email:jcolibri@jcolibri.com
Copyright © J.Colibri   http://www.jcolibri.com - 2001 - 2015
Retour:  Home  Articles  Formations  Développement Delphi  Livres  Pascalissime  Liens  Download
l'Institut Pascal

John COLIBRI

+ Home
  + articles_avec_sources
    + bases_de_donnees
    + web_internet_sockets
      – http_client
      – moteur_de_recherche
      – javascript_debugger
      + asp_net
        – cassini_installation
        – tutorial_asp_net
      – client_serveur_tcp
      – site_editor
      – pascal_to_html
      – cgi_form
      + les_logs_http_bruts
      + les_blogs
      – intraweb_tutorial
      + services_web
      – serveur_web_iis
      – client_serveur_pop3
    + prog_objet_composants
    + office_com_automation
    + colibri_utilities
    + uml_design_patterns
    + graphique
    + delphi
    + outils
    + firemonkey
    + vcl_rtl
    + colibri_helpers
    + colibri_skelettons
  + formations
  + developpement_delphi
  + présentations
  + pascalissime
  + livres
  + entre_nous
  – télécharger

contacts
plan_du_site
– chercher :

RSS feed  
Blog

Formation Delphi 7 complete L'outil de développpement, le langage de programmation, les composants, les bases de données et la programmation Internet - 5 jours
Formation Bases de Données Delphi Gestion de bases de données : connexion, accès aux tables, édition d'états - 3 jours