Le développement Intraweb avec Delphi

Dany Leblanc

Delphi est essentiellement connu comme étant un environnement de développement permettant de construire rapidement des applications riches et robustes pour Windows, Mac et mobiles. Son utilisation pour la réalisation d'applications destinées à s'exécuter dans un navigateur est moins connue. Il dispose pourtant de quelques frameworks lui permettant d'apporter ses atouts également à ce type de projet. Je propose dans cet article de présenter Intraweb, qui est un produit de la société Atozed software et qui est probablement le framework le plus connu puisque sa version bundle est intégrée à Delphi.

Commentez

- Titre : Le développement Intraweb avec Delphi

- Auteur : Dany Leblanc

- Parution : 14 octobre 2015

- Mise à jour : 6 décembre 2015

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2015 Dany Leblanc. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Présentation

- II. Installation

- III. Première application

- IV. Synoptique d'un projet Intraweb

- IV-A. ServerController.pas

- IV-B. UserSessionUnit.pas

- IV-C. Datamoduleunit.pas

- V. Le ServerController

- VI. Les sessions

- VII. Le pool de connexions

- VIII. L'objet WebApplication

- VIII-A. Récupération des paramètres

- VIII-B. Gestion des cookies

- VIII-C. Affichage d'un message d'alerte

- VIII-D. Terminaison de l'application

- VIII-E. Envoyer un fichier vers le navigateur

- IX. Sélectionner la page d'entrée de l'application

- IX-A. La méthode la plus simple

- IX-B. Sélection dynamique du formulaire à afficher au démarrage

- IX-C. Un peu plus loin

- X. Organisation de l'application sur le disque

- XI. Utilisation des templates

- XII. Utilisation des CSS

- XIII. Utiliser les frames

- XIV. Création d'un frame

- XIV-A. Utilisation d'un frame

- XV. Les appels asynchrones

- XVI. Utilisation de JavaScript

- XVI-A. Coder un événement en JavaScript

- XVI-B. Écriture de code JavaScript plus volumineux

- XVI-C. Paramètres pour le JavaScript au niveau de l'application

- XVII. Annexes

- XVII-A. Les principales propriétés de la classe TIWServerController

- XVII-A-1. AllowMultipleSessionPerUser

- XVII-A-2. AppName

- XVII-A-3. AuthBeforeNewSession

- XVII-A-4. Auther

- XVII-A-5. BackButtonOptions

- XVII-A-6. BoundIP

- XVII-A-7. CacheDir

- XVII-A-8. ComInitialization

- XVII-A-9. Compression

- XVII-A-10. Description

- XVII-A-11. DisplayName

- XVII-A-12. Port

- XVII-A-13. SessionTimeout

- XVII-A-14. StyleSheet

- XVII-A-15. TemplateDir

- XVII-B. Les événements de la classe TIWServerController

- XVII-B-1. OnNewSession

- XVII-B-2. OnException

- XVII-B-3. OnLogException

- XVIII. Remerciements

I - Présentation

Intraweb est un framework permettant de créer des applications HTML avec Delphi. L'idée était de porter les points forts de Delphi également pour le développement web. Avec ce framework, nous allons pouvoir écrire simplement des applications web et les déployer, soit :

- avec un serveur web inclus ;

- sous forme de dll ISAPI pouvant être déployée sous IIS ;

- en ASPx (pour la dernière version d'Intraweb).

II - Installation

Intraweb fait partie du package standard de RAD Studio. Cependant, il est préférable de ne pas garder cette version, mais d'aller télécharger gratuitement la dernière version sur le site de l'éditeur, à savoir Atozed Software. Ceci permettra de s'enregistrer et d'être informé des mises à jour du produit, voire de récupérer celles disponibles pour la version bundle. Je vous propose dans ce chapitre de détailler la procédure à suivre pour faire cette mise à jour.

La première chose à faire est de demander notre clé de licence. Pour cela, nous allons sur la partie du site Atozed purchase point. La première chose à renseigner est notre adresse de courriel. Après avoir cliqué sur « Next », soit notre adresse est déjà connue et nous pouvons saisir notre mot de passe, soit le site propose de poursuivre pour nous enregistrer. Je passe la procédure classique de création d'un compte utilisateur. Donc, une fois le mot de passe saisi, on arrive sur la page récapitulant nos informations. Tout en bas de cette page, il existe un lien nommé Intraweb, cliquons dessus. Nous arrivons alors sur cette page :

La partie haute permet d'acheter une licence payante et de gérer nos éventuelles licences déjà acquises. Nous allons nous intéresser à la partie du bas et cliquer sur « Request Bundled License » (on peut noter au passage qu'Atozed propose une ancienne version complète et gratuite).

Dans la page suivante, on va devoir renseigner les informations concernant notre licence RAD Studio et surtout leur indiquer la chaîne « IDE hash string » (eh oui ce téléchargement n'est accessible que pour les détenteurs d'une licence RAD Studio et en plus il sera différent suivant que nous avons la version Professionnelle ou Entreprise).

Pour obtenir la chaîne de caractères à entrer dans cette page, Atozed propose un petit outil en téléchargement (nous le téléchargeons même si nous avions déjà fait la procédure pour une précédente version de Delphi). Cet outil propose une interface toute simple :

Nous choisissons notre version de RAD Studio, nous pouvons modifier le répertoire d'installation si ce n'est pas celui qui est proposé, et nous cliquons sur « Generate ». Voilà, la clé est générée, et l'outil a même été jusqu'à la copier dans le presse-papier ; nous n'avons donc plus qu'à la coller sur la page web précédente. Enfin, nous cliquons sur « Request ». Nous allons recevoir la clé d'enregistrement dans notre boite mail. Elle restera également disponible sur le lien « My keys » de l'écran principal d'Atozed purchase point.

Ceci étant fait, nous pouvons nous rendre sur la page des téléchargements pour récupérer la dernière version disponible pour notre édition de RAD Studio.

L'étape suivante va consister à supprimer la version qui a été installée avec Delphi (ceci sera d'ailleurs la procédure à suivre pour toute mise à jour d'une version d'Intraweb). Il faut donc pour cela retourner dans l'installateur de RAD Studio, de choisir « Modifier » et de désélectionner « Intraweb » :

Nous validons ensuite l'installation et attendons la fin de cette dernière pour continuer.

Mais ceci ne sera pas suffisant, nous allons devoir supprimer les fichiers laissés sur le disque par le désinstalleur. Heureusement, depuis quelque temps Atozed fournit un petit outil qui se charge de cette tâche fastidieuse et délicate. Cet outil est téléchargeable ici : RemovalTool.

L'utilisation de cet outil est encore une fois très simple :

On choisit notre version de Delphi, puis on clique sur le bouton « Remove ». La liste des fichiers supprimés défile. Une fois terminé, on ferme cet outil.

Il ne reste donc plus qu'à lancer l'installeur d'Intraweb que nous avons précédemment téléchargé. Durant cette installation, la clé reçue par mail sera demandée pour pouvoir continuer.

Voilà, nous sommes prêts à développer des applications web avec Delphi et Intraweb.

III - Première application

Pour commencer notre application, créons le projet Intraweb. Pour ce faire, comme pour n'importe quel projet, cela commence par la boite de dialogue de nouveau projet, dans laquelle nous pouvons trouver une ligne « Intraweb » que nous sélectionnons :

Sélectionner « Intraweb Application Wizard », un nouveau dialogue s'affiche :

Nous pouvons ici sélectionner le type d'application que nous souhaitons réaliser :

- Standalone Application : il s'agit d'une application incluant un serveur web et qui peut donc s'exécuter sans passer par IIS.
Ce type d'application est très pratique pour déboguer notre programme.
Mais ce type d'application peut très bien être déployé en production, puisqu'il y a possibilité de l'installer en tant que service Windows. Ceci peut s'avérer une bonne solution d'ailleurs pour éviter de monter tout un serveur IIS si on n'a pas d'autre besoin de publication que notre application ;

- ISAPI Extension : ce type d'application va permettre de créer une dll qui sera ensuite déployée sur un serveur IIS. Ceci est pratique si vous avez déjà un serveur IIS, et indispensable si vous devez diffuser plusieurs applications sur le même port d'écoute.

Nous avons également la possibilité de choisir des options :

- Pool Data Connection : si cette option est cochée, le template de projet va générer les méthodes nécessaires permettant de gérer un pool de Datamodules qui pourront être attribués à la volée lorsque le programme en aura besoin. Nous verrons un peu plus bas comment gérer cela ;

- Use ISAPIThreadPool : option disponible uniquement dans le cas d'un projet de type ISAPI Extension, elle ajoute juste un uses permettant d'utiliser la fonctionnalité IIS qui permet de threader les pools.

Nous choisissons pour l'exemple une application de type standalone et nous ne nous occupons pas des options pour le moment. Après avoir cliqué sur « Ok », notre nouveau projet est créé.

Le template de création du projet nous a donc créé trois unités que nous verrons en détail plus bas :

- ServerController, qui représente le serveur ;

- Unit1

, qui est notre formulaire principal ; nous le renommons ufrmMain et le formulaire s'appellera frmMain ;

- UserSessionUnit, qui est un datamodule qui va pouvoir contenir tous les éléments nécessaires à la session de l'utilisateur.

Habituellement lorsqu'on veut faire une première démo sur une technologie web, on fait un classique « Hello world ». Avec Delphi et le framework Intraweb, je vais me permettre une démo un tout petit peu plus ambitieuse. Je vous propose donc de faire une petite application toute simple d'affichage d'une table d'une base de données avec possibilité de recherche.

Nous allons donc dans un premier temps nous intéresser uniquement à l'unité « ufrmMain » qui va être notre formulaire principal. Comme dans un projet VCL classique, nous disposons d'un dfm sur lequel nous allons pouvoir poser nos composants. La première petite différence va se situer sur la palette de composants à utiliser. Il ne va pas falloir bien entendu utiliser les composants de la VCL, mais leurs équivalents qui se trouvent dans les palettes dont le nom commence par « Intraweb ».

Les noms des composants Intraweb commencent par « TIW ».

Nous posons donc sur notre formulaire un TIWEdit, un TIWButon et un TIWDbgrid, pour obtenir quelque chose comme ceci :

Nous nommerons ces composants respectivement iwdt1, btn1 et grd1.

Pour les données, nous allons utiliser la base exemple Employee.gdb, que nous accéderons avec les composants Firedac, mais bien entendu cela reste valable avec toute autre base de données et également avec les composants dbExpress, ou autres.

Il va donc falloir ajouter quelques composants, non visuels ceux-ci, à notre formulaire :

Tout d'abord pour l'accès à notre table :

- un TFDConnection que nous nommons cnxEmployees ;

- un TFDGuidxWaitCursor que nous nommons fdw1 ;

- un TFDQuery que nous nommons qryEmployees.

Un clic droit sur le TFDConnection permet d'accéder à l'éditeur de connexion qui va permettre de paramétrer la connexion à la base de données exemple :

Une fois ceci fait, on va sur le composant TFDQuery pour saisir notre requête. Un double-clic sur ce dernier permet de saisir et de tester celle-ci :

Voilà, c'est tout pour l'accès à la table.

Une fois ce dialogue validé, on peut passer la propriété « Active » du composant à « True ».

Posons un autre composant qui va permettre de lier les composants visuels à ces données :

- un Tdatasource.

Le paramétrage de ce composant est également très simple puisqu'il suffit de renseigner la valeur de la propriété « Dataset » du composant TDatasource par le nom du composant TFdQuery (qryEmployees dans notre exemple).

De plus, la propriété possède une liste déroulante permettant de choisir le nom.

Pour terminer, renseignons de la même manière la propriété « Datasource » du TIWDbGrid avec le nom du TDatasource. Toujours sur le TIWDBGrid, on va mettre la propriété « UseFrame » à false.

Voilà, un petit appui sur la touche de fonction F9 permet de compiler et exécuter notre application, ce qui va nous donner ceci :

Rien à voir avec notre formulaire bien entendu, il s'agit en fait du serveur intégré à Intraweb (rappelons-nous : nous avons choisi une application standalone). Il faut faire à nouveau F9 pour voir le navigateur s'ouvrir et afficher le résultat qui devrait ressembler à cela :

Bien, notre exemple n'est toutefois pas complet, il faut ajouter une possibilité de recherche. Revenons donc dans Delphi, et effectuons un double-clic sur le bouton que nous avons posé précédemment, afin d'implémenter l'action de ce dernier. Il suffit alors de saisir ces quelques lignes de code :

procedure TIWForm1.btn1Click(Sender: Tobject);
begin
qryEmployees.Active := False;
qryEmployees.Filter := 'full_name like ' + QuotedStr( '%' + iwdt1.Text + '%');
qryEmployees.Filtered := True;
qryEmployees.Active := True;
end;

Voilà, exécutons l'application. Il est à présent possible de faire une recherche par nom sur notre liste d'employés.

À présent notre premier projet est terminé. On peut voir qu'en très peu de temps, et avec seulement quelques lignes de code, nous avons réussi à faire un petit programme web fonctionnel. Certes il n'est pas très élaboré d'un point de vue esthétique, mais nous allons voir dans les pages qui suivent comment faire de belles applications web en utilisant tous les concepts connus et standards du web, tout en continuant de coder avec Delphi.

IV - Synoptique d'un projet Intraweb

À présent, arrêtons-nous un peu sur ce qui a été généré par le template de projet. Nous venons de voir l'unité UfrmMain.pas, qui est le formulaire principal par défaut de notre application, mais suivant les options choisies deux ou trois autres unités ont été créées pour notre projet. Il s'agit de :

- DatamoduleUnit.pas (créée uniquement si on choisit l'option « DataPoolConnection ») ;

- ServerController.pas ;

- UserSessionUnit.pas.

IV-A - ServerController.pas

Cette unité contient une classe TIWServerController qui va regrouper tous les paramètres du serveur que nous développons. Nous reviendrons plus tard en détail sur cette unité particulière.

IV-B - UserSessionUnit.pas

Nous trouvons ici une classe TIWUserSession. Une instance de cette classe est créée pour chaque utilisateur connecté, on peut donc y mettre tous les objets et variables nécessaires à la session. Un dfm est également créé, on peut donc y déposer des composants non visuels comme une connexion à une base de données par exemple.

IV-C - Datamoduleunit.pas

Cette unité n'est créée que lorsque l'option « Data pool Connection » a été cochée. C'est un datamodule classique, que tous les Delphinautes connaissent. Il sert donc exactement à la même chose.

La différence se situe au fait que le serveur va gérer les instances de ce datamodule et les fournira à la demande. L'instance fournie sera prise dans un pool de n instances, n étant paramétrable via la propriété « PoolCount » du composant TIWDatamodulePool dont une instance a été automatiquement ajoutée au TIWServerController lors de la création du projet.

V - Le ServerController

Cette unité contient une classe TIWServerController qui, comme son nom le suggère, va permettre de contrôler le serveur et son environnement.

C'est avec cette classe que nous allons pouvoir :

- fixer le port d'écoute de notre application. Attention : ceci n'est pas vrai si vous choisissez de ne pas télécharger la version bundle sur le site d'Atozed puisque dans ce cas le port est attribué de façon aléatoire au démarrage du serveur ;

- déterminer le temps d'inactivité durant lequel la session utilisateur reste en mémoire. Passé ce laps de temps (exprimé en minutes) tout appel à la session provoquera un message d'erreur de type Session Timeout ;

- définir le mode de gestion du numéro de session à l'aide de la propriété « AllowMultipleSessionPerUser ». Celle-ci est à false par défaut. Dans ce cas, le numéro de session est stocké dans un cookie. Par conséquent lorsqu'une session est démarrée, toute nouvelle instance de navigateur sur un même poste utilisera la même session. Si elle est cochée, alors le numéro de session est passé dans l'URL, on peut donc avoir autant d'instances d'application que de navigateurs ou d'onglets.

Nous détaillerons les autres principales options de cette classe en annexe.

VI - Les sessions

Un des gros atouts d'Intraweb est la gestion intégrée des sessions. C'est la classe TIWUserSession de l'unité UserSessionUnit.pas qui va être chargée de cela. Une instance de cette classe est créée pour chaque session. Elle possède peu de propriétés, par contre elle vient avec un dfm, comme un DataModule. On peut donc y déposer des composants non visuels dont on a besoin pour la session, comme une connexion à la base de données, un composant Report (Rave, FastReport…).

La gestion à proprement parler se fait à partir de l'objet IWServerController. Dans cet objet, on va notamment pouvoir définir :

- son délai de « TimeOut », c'est-à-dire le délai d'inactivité à partir duquel la session est considérée comme obsolète et est détruite ;

- la gestion de son ID. Chaque session possède un ID unique. Ce dernier peut être géré soit par l'URL (dans ce, cas il transite avec chaque appel serveur), soit par cookie (il est à ce moment-là invisible de l'utilisateur). Une autre différence entre les deux modes est que lorsqu'elle est gérée par cookie, on ne peut avoir qu'une seule session active par poste client, puisque tous les navigateurs vont lire le même cookie.

Maintenant, reprenons notre petite application. Nous n'avons utilisé que l'unité ufrmMAin sur laquelle nous avons posé tous les composants. Nous allons réorganiser cela afin de pouvoir réutiliser certains composants dans de nouveaux formulaires. Pour cela, ouvrons à nouveau l'unit ufrmMain et nous sélectionnons les composants TFDConnection, TFDWaitcursor, TFDquery puis nous les déplaçons sur le dfm de l'unité IWUserSessionUnit. Nous avons donc à présent quelque chose qui ressemble à cela :

Revenons sur notre formulaire.

Le correcteur de syntaxe nous indique qu'il existe des erreurs, ce qui est normal puisque nous avons enlevé des composants. Pour supprimer ces erreurs, commençons déjà par ajouter les références nécessaires dans la clause uses :

uses
UserSessionUnit, ServerController;

Puis, QryEmployees faisant maintenant partie de l'objet UserSession, il faut modifier la méthode de recherche ainsi :

procedure TIWForm1.btn1Click(Sender: TObject);
begin
UserSession.qryEmployees.Active := False;
UserSession.qryEmployees.Filter := 'full_name like ' + QuotedStr( '%' + iwdt1.Text + '%');
UserSession.qryEmployees.Filtered := True;
UserSession.qryEmployees.Active := True;
end;

Il ne reste plus qu'à modifier le lien Dataset du TDataSource et le tour est joué :

VII - Le pool de connexions

Nous avons vu lors de la création d'un projet Intraweb qu'il est possible de demander un pool de connexions. Cette fonctionnalité va permettre de partager n instances d'un TDatamodule entre tous les utilisateurs, chaque instance n'étant bien entendu utilisée que par un seul utilisateur à la fois. L'intérêt de ceci est de pouvoir disposer d'un Datamodule déjà créé (s'il en existe un libre dans le pool), ce qui va améliorer les performances.

Lorsque cette option est sélectionnée, le template de projet rajoute un composant sur le ServerController, il s'agit d'un TIWDataModulePool. Il va permettre le paramétrage du pool et son activation. Le paramétrage est on ne peut plus simple puisqu'il consiste à indiquer via la propriété PoolCount combien d'instances de TDatamodule peuvent être contenues dans le pool.

Il dispose également de deux événements :

- OnCreateDatamodule : généré lors de l'initialisation du pool, il permet la création de n instances du Datamodule ;

- OnFreeDatamodule : permet de libérer les instances contenues lors de la désactivation du pool ou lors de sa destruction.

Deux fonctions sont également ajoutées au ServerController, ce sont deux fonctions globales :

- LockDatamodule : cette fonction retourne une instance du Datamodule, en la prenant parmi celles disponibles dans le pool. Remarque : si le pool est plein et qu'aucune instance n'est libre, alors une exception est levée ;

- UnlockDatamodule : cette méthode permet à une session de libérer le Datamodule qu'elle s'est octroyé à l'aide de la méthode LockDatamodule. Après l'appel de cette fonction, il ne sera pas détruit, mais sera placé dans le pool en statut disponible pour une autre session qui en aurait besoin.

Bien entendu, ce principe possède des avantages indéniables ; il ne faut cependant pas oublier qu'on récupère une instance qui vient d'être utilisée, il faut donc faire attention à l'état des composants et prendre pour principe, soit de les initialiser au moment où on prend possession de l'instance, soit de les réinitialiser avant de libérer l'instance une fois qu'on en a plus besoin.

VIII - L'objet WebApplication

Comme son nom le laisse aisément deviner, cet objet représente l'application web. Il va nous permettre d'en récupérer le contexte et d'interagir avec.

VIII-A - Récupération des paramètres

Un des premiers intérêts de WebApplication est sans aucun doute la possibilité de récupérer les paramètres passés à notre application, soit par l'URL, soit par un formulaire. L'ensemble de ces paramètres va se retrouver dans la propriété RunParams qui est sous la forme classique d'un TStrings. Ainsi WebApplication.RunParams[ ‘Action'] va nous retourner la valeur du paramètre Action, qu'il soit passé par l'URL ou bien reçu par formulaire. Si le paramètre n'est pas présent alors la valeur retournée est vide.

Bien entendu on va également pouvoir discerner la provenance des paramètres de façon plus classique avec la propriété Request, de type THTTPRequest. L'objet Request contient notamment deux propriétés :

- QueryFields : de type TStrings, il contient les paramètres reçus dans l'URL. Son utilisation est identique à RunParams ;

- ContentFields : de type TStrings, il contient les paramètres reçus par formulaire.

VIII-B - Gestion des cookies

C'est également avec cet objet que nous allons pouvoir gérer les cookies, à l'aide de deux méthodes.

Écrire un cookie :

webApplication.Response.AddCookie(   aName : string ; aValue : string ; aPath : string ; aExpires : TDateTime) ;

- aName : nom de notre cookie ;

- aValue : sa valeur ;

- aPath : permet de restreindre l'accès au cookie à certains chemins de l'URL (‘/' pour toute l'application) ;

- permet d'indiquer une date de péremption du cookie.

Lire un cookie :

webApplication.GetCookieValue(  aName:string ) :string;

- aName : nom du cookie dont on souhaite la valeur.

Si le cookie existe et est valide, la fonction retourne sa valeur.

VIII-C - Affichage d'un message d'alerte

Il s'agit du classique Alert Javascript. Si nous avons besoin d'envoyer un simple message à l'utilisateur, nous pouvons le faire à l'aide de cette méthode :

webApplication.ShowMessage( ‘Hello') ;

Cette méthode accepte deux autres paramètres :

- AType : permet de définir la forme de la boite de dialogue :

- smAlert : c'est la valeur par défaut, le message s'affiche comme le standard alert() du JavaScript,

- smNewWindow : le message est affiché dans une nouvelle fenêtre en popup,

- smSameWindows : le message apparaît à la place de la page actuelle. Un bouton permet de le fermer et de revenir à notre page,

- smSameWindowFrame : identique au précédent, mais le message est placé dans une région qui permet de scroller si le texte est long ;

- aTemplate : uniquement pour le type smSameWindows ou smSameWindowFrame. Ce paramètre permet de fournir un template HTML pour l'affichage du message. Les tags utilisés sont {%textMessage%} pour le message, et {%butnOk%} pour le bouton OK.

VIII-D - Terminaison de l'application

Chaque application Intraweb possède naturellement une session. C'est très pratique et un gros plus par rapport à certaines autres technologies qui laissent la gestion de session à la charge du développeur. L'inconvénient de ceci est qu'un minimum de mémoire est nécessaire pour chaque session. Sachant cela il devient évident qu'il faut éviter la multiplication des sessions non utilisées. On ne peut jamais obliger un utilisateur, mais la présence d'un bouton « Quitter » peut l'inciter à fermer par ce moyen plutôt qu'à s'en aller brutalement. Et si l'utilisateur clique sur ce bouton, alors nous avons deux possibilités de fermer l'application :

- WebApplication.Terminate : détruit simplement la session et retourne une page blanche. Un paramètre de type string peut lui être passé, auquel cas il sera affiché à l'utilisateur. Il peut bien entendu contenir du code HTML ;

- WebApplication.TerminateAndRedirect : plus intéressant, il permet de préciser une URL de destination. Dans ce cas la session est détruite (et la mémoire occupée libérée) et l'utilisateur est redirigé vers l'URL passée en paramètre.

VIII-E - Envoyer un fichier vers le navigateur

On a souvent besoin de proposer des fichiers à télécharger à l'utilisateur. Une possibilité pour faire cela réside dans la méthode SendFile :

webApplication.SendFile( const aPathname: string; const aAttachment: Boolean = False; aContentType: string = ''; aFilename: string = '') ;

- aPathName doit contenir le chemin du fichier à envoyer (il doit bien entendu être accessible depuis le serveur Intraweb) ;

- aAttachment : True : avec ce mode, l'utilisateur va pouvoir choisir d'enregistrer le fichier téléchargé ou bien de l'ouvrir dans le navigateur. False : dans ce cas le fichier sera ouvert par l'application installée sur le poste client ;

- aContentType : permet de renseigner le header HTML du même nom ;

- aFileName : permet de proposer à l'utilisateur un nom différent de celui d'origine.

IX - Sélectionner la page d'entrée de l'application

IX-A - La méthode la plus simple

Nous l'avons vu, le template nous a créé notre page principale et nous n'avons rien eu à faire pour qu'elle s'affiche directement au démarrage de l'application. Ceci est possible grâce à la section « Initialization »  de notre formulaire principal :

initialization
TIWForm1.SetAsMainForm;

L'appel de cette méthode va indiquer à Intraweb quel est le formulaire principal et donc lequel afficher au démarrage. Dans ce cas-là nous n'avons donc rien de plus à faire.

IX-B - Sélection dynamique du formulaire à afficher au démarrage

Cependant cela n'est pas toujours satisfaisant. En effet on peut parfois avoir besoin de deux ou N points d'entrée dans notre application, selon l'utilisateur qui se connecte, par exemple, ou encore en fonction de paramètres passés dans l'URL. Et là nous voyons que cela n'est pas possible à réaliser avec la méthode proposée plus haut.

Mais bien évidemment, Atozed a prévu ce cas de figure. Ainsi le ServerController propose un événement OnGetMainForm qui va permettre de préciser le formulaire à afficher au début de la session. La méthode générée possède un paramètre var de type TIWBaseForm : MainForm. Ce paramètre va représenter le formulaire d'entrée de l'application.

procedure TIWServerController.IWServerControllerBaseGetMainForm(
var vMainForm: TIWBaseForm);
begin

end ;

On va donc pouvoir instancier un formulaire différent, en fonction par exemple d'un paramètre de l'URL. Imaginons que notre application possède une partie administration, et nous avons décidé qu'on y accéderait en passant un paramètre dans l'URL, par exemple mode=Admin. Nous allons donc tester la présence de ce paramètre dans l'URL :

procedure TIWServerController.IWServerControllerBaseGetMainForm(
var vMainForm: TIWBaseForm);
begin
if WebApplication.RunParams.Values[ 'Mode'] = 'Admin' then
begin
vMainForm := tIWAdminForm.Create( WebApplication) ;
end
else
begin
vMainForm := TIWForm1.Create( WebApplication);
end;
end ;

Nous pouvons écrire cela parce que TIWBaseForm est l'ancêtre de TIWAppForm. C'est une instanciation de classe classique. Nul besoin de lui préciser de l'afficher, le framework s'en chargera tout seul.

Dans ce cas, bien entendu la section « initialization » de notre formulaire précédent devient caduque et doit être supprimée.

IX-C - Un peu plus loin

Comme nous l'avons vu, nous avons toute la souplesse nécessaire pour élaborer une application volumineuse. Cependant, si le nombre de possibilités de points d'entrée devient plus important, la technique vue dans le paragraphe précédent risque de devenir assez lourde et difficile à maintenir et à faire évoluer. Je vous propose donc de voir une méthode un peu plus élégante en utilisant un pattern de chaîne de responsabilité.

Pour commencer, créons une unité simple que nous nommons uInvokerActions. Dans celle-ci nous définissons une interface à laquelle devra répondre chaque classe de la chaîne :

Uses
System.Classes , System.SysUtils,
IWServerControllerBase, IWBaseForm, HTTPApp,
// For OnNewSession Event
UserSessionUnit, IWApplication, IWAppForm;

type
IAction = interface
['{EDD3F333-F82D-4618-B49D-450E02D3C16C}']
function HandleAction(var VMainForm: TIWBaseForm):boolean;
end;

Puis nous allons créer une classe singleton qui va être chargée de gérer cette chaîne. Appelons-la TInvokerActions :

TInvokerActions = class( TInterfacedObject, IAction)
private
FActionList : TInterfaceList;

class var FInvoker: TInvokerActions;
public
constructor Create;
destructor Destroy; override;

class destructor DestroyClass;

class function GetInvokerActions: TInvokerActions;

procedure AddAction( aAction : IAction);
procedure RemoveAction( aAction: IAction);
procedure NotifyActions(var VMainForm: TIWBaseForm);
end;

La méthode la plus importante ici est la méthode NotifyActions :

procedure TInvokerActions.NotifyActions(var VMainForm: TIWBaseForm);
var
I: Integer;
wHandledAction: Boolean;
begin
wHandledAction := False;

for I := 0 to FActionList.Count - 1 do
begin
wHandledAction := IAction( FActionList[ I]).HandleAction(VMainForm);

if wHandledAction then
Break;
end;

if not( wHandledAction) then
begin
raise Exception.Create('Action non définie');
end;
end;

Reste à définir les « actions ». Une classe faisant partie de la chaîne devra donc hériter de IAction et implémenter la méthode HandleAction. Par exemple, créons une nouvelle unité simple que nous appellerons uActMain :

Uses
uInvokerActions;

type
TActMain = class( TInterfacedObject, IAction)
Public
function HandleAction(var VMainForm : TIWBaseForm) :Boolean ;
End ;

implementation

uses ufrmMain;

Function TActMain.HandleAction(var VMainForm : TIWBaseForm) :Boolean;
Begin
If  ( WebApplication.Request.ContentFields.Values[ ‘Action'] = ‘Main' ) then
Begin
VMainForm := TfrmMain.Create( WebApplication) ;
Result := True ;
End
Else
Begin
Result := False ;
End ;
End ;

Initialization
TInvokerActions.GetInvokerActions.AddAction( TActMain.Create) ;

Donc, on le voit dans cet exemple très simple, si le paramètre « Action » a la valeur « Main », on va instancier le formulaire correspondant (ici TfrmMain), puis retourner la valeur true et dans ce cas la chaîne va s'arrêter. Sinon la méthode NotifyAction passera à l'action suivante dans sa liste jusqu'à ce qu'une d'entre elles retourne true. Et si aucune action ne répond, alors il faut prévoir l'affichage d'un message à l'utilisateur.

Note : ne pas oublier la section Initialization dans chaque classe de la chaîne afin que celle-ci soit enregistrée dans la liste des actions.

Revenons à présent dans l'unité ServerController, ajoutons uInvokerActions dans les uses. Éditons l'événement IWServerControllerBaseGetMainForm. Il ne nous reste plus qu'à remplacer la suite des tests par une simple ligne de code :

TInvokerActions.GetInvokerActions.NotifyActions( VMainForm) ;

Bien entendu, à présent il faut passer en paramètre de l'application l'action que nous souhaitons invoquer. Si nous tentons de l'exécuter comme au début de ce tutoriel, sans préciser l'action, nous obtiendrons logiquement le message généré par notre méthode « NotifyAction » :

Le paramètre peut se passer classiquement via l'URL ou bien il est possible de le mentionner sur le serveur Intraweb dans l'onglet « Server » :

Cliquons sur l'icône du navigateur, notre application se lance à nouveau sur l'affichage de notre liste.

Avec cette méthode, ajouter un nouveau point d'entrée à notre application consistera à ajouter une nouvelle classe identique à TActMain.

X - Organisation de l'application sur le disque

Une application web n'est rarement constituée que de code, elle fait souvent appel à des images, des scripts… Tous ces éléments ne sont pas encapsulés dans l'application, il faut donc les placer quelque part sur notre serveur.

Donc le répertoire racine de notre serveur va être le répertoire d'installation de l'exécutable. Au même niveau que l'exécutable, nous placerons deux répertoires :

- Templates : ce répertoire contiendra tous les fichiers HTML qui serviront de template pour nos formulaires ;

- wwwRoot : ce répertoire va être la racine de tous les autres fichiers tels que CSS, JS, images. Il est aussi possible de créer d'autres niveaux à l'intérieur de ce dossier.

XI - Utilisation des templates

Nous allons voir maintenant comment améliorer le visuel de notre application, et aussi le déléguer à un designer professionnel. Ceci va être possible à l'aide des templates HTML. Ce sont en fait des fichiers HTML classiques qui vont pouvoir contenir tout ce que peut contenir un fichier HTML, et dans lesquels nous allons pouvoir positionner nos composants à l'aide de tags qui seront remplacés dynamiquement lors de l'affichage de la page.

Ces tags devront respecter la forme suivante : {%NomDuComposant%}. Par exemple, si nous avons un label qui se nomme lblNom, son tag sera {%lblNom%}.

Appliquons cela à notre petit projet. Commençons donc par ajouter un fichier HTML à notre projet. Pour cela nous choisissons d'ajouter un élément, et nous choisissons la catégorie Documents Web :

Nous allons nous contenter de centrer les éléments, et d'ajouter un texte devant la zone d'édition :

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>
<head>
<title></title>
</head>

<body>
<div align="center">
Rechercher&nbsp;:&nbsp;{%iwdt1%}&nbsp;{%btn1%}<br/>
{%grd1%}
</div>
</body>
</html>

Ceci étant fait, il faut sauvegarder ce fichier dans le répertoire « Templates », comme vu plus haut. Appelons-le ufrmMain.htm par exemple.

Le lien entre ce fichier HTML et notre form va se faire à l'aide du composant TIWTemplateProcessorHTML. Posons-en un sur notre formulaire, puis renseignons sa propriété Templates.Defaut à « ufrmMain.htm » (il n'est pas nécessaire de préciser le chemin puisque le serveur ira le chercher dans le sous-répertoire « Templates ». Il ne reste plus qu'à lier ce composant au formulaire en le sélectionnant dans la propriété LayoutMgr de celui-ci. Le lien n'est pas automatique puisque rien n'empêche d'avoir plusieurs templates interchangeables dynamiquement.

Voilà, maintenant à l'exécution, nos composants sont centrés à l'écran :

XII - Utilisation des CSS

Une autre façon de modifier l'apparence d'une page web consiste à utiliser les feuilles de style. Bien entendu, cela est tout à fait possible avec Intraweb.

Retournons donc dans les nouveaux éléments, onglet « Documents Web » et cette fois-ci, sélectionnons « Feuilles de styles CSS » :

Enregistrons le fichier obtenu dans le répertoire wwwRoot. Nommons-le par exemple « Styles.css ».

Nous allons dans un premier temps modifier l'apparence du bouton de recherche pour lui arrondir les coins. Pour cela nous définissons un style « Bouton » comme suit :

.Bouton{
border-radius:8px;
}

Contrairement aux unités Delphi, les fichiers HTML, CSS, JS ne sont pas inclus dans l'exécutable, ils sont chargés à l'exécution par le serveur ; nous sommes dans le fonctionnement web classique. Il faut donc toujours penser à sauvegarder les modifications pour qu'elles soient prises en compte.

Si nous exécutons l'application maintenant, nous pouvons constater que rien ne change. Ceci est parfaitement normal, d'abord nous n'avons pas redéfini la balise « input », donc rien ne dit au navigateur à quel élément il doit appliquer ce style. Et surtout, nulle part nous n'avons lié la feuille de style à notre page. Ceci peut se faire à plusieurs endroits :

- dans l'objet TIWServerController, nous disposons d'une propriété StyleSheet de type TIWFileReference qui est une classe contenant deux propriétés : FileName et URL. Nous renseignons FileName avec le nom de notre fichier CSS : Styles.css (attention à respecter la casse). Pas besoin de préciser de chemin, il va le chercher à la racine de wwwRoot ;

- au niveau de chaque formulaire. Selon le principe même des CSS, on peut redéfinir un style à tout moment. On dispose donc dans chaque formulaire de cette même propriété StyleSheet permettant d'indiquer une feuille de style différente.

Voilà, il ne nous reste plus qu'à indiquer sur quel élément nous voulons appliquer le style « Bouton ». Cela se passe donc sur notre formulaire, sur l'objet TIWButton qui possède, comme la quasi-totalité des composants Intraweb, une propriété « CSS ». C'est dans cette propriété que nous écrivons « Bouton ». Exécutons l'application, nous voyons à présent que le bouton est arrondi :

Attaquons-nous un peu à la grille qui n'est pas très jolie puisqu'elle est affichée là dans sa plus simple représentation.

Donc, commençons par compléter notre feuille de style. Ce coup-ci nous allons décider que toutes les grids de notre application auront le même aspect, nous allons donc directement redéfinir les styles des balises concernées :

table {
border-collapse: collapse;
width: 100%;
}

table, th, td {
border: 1px solid green;
}

th {
height: 50px;
background-color: green;
color: white;
}

Si nous exécutons à nouveau l'application, nous nous apercevons que malheureusement la grid a toujours le même aspect. C'est la contrepartie de la simplicité du framework Intraweb. Ils ont prédéfini des styles pour les composants, et ceux-ci sont définis au niveau même des éléments HTML, afin d'offrir une solution la plus encapsulée possible. Seulement, vu qu'ils sont définis au niveau de l'élément, suivant le principe des CSS, ils remplacent tous ceux qu'on pourrait définir en amont. Mais ceci n'est pas une fatalité, nous allons juste devoir, par quelques manipulations, indiquer que nous ne voulons pas des styles prédéfinis.

Sélectionnons la grid, et intéressons-nous à la propriété StyleRenderOptions. Cette propriété contient un certain nombre d'options qui sont cochées par défaut. Lorsqu'elle est cochée, ceci indique que le style prédéfini est appliqué au niveau du composant. Décochée, Intraweb ne l'appliquera pas. Nous décochons donc toutes ces options pour garder au maximum le contrôle de l'apparence. Inutile par contre de décocher l'option Z-Index, on peut le laisser la gérer.
Cette propriété se retrouve pour chaque composant, il faudra donc penser à la modifier dès lors que nous souhaiterons utiliser des styles personnalisés.

Pour la grid, nous avons également une propriété CellRenderOptions, qui contient également des cases à cocher que nous décochons.

Une dernière opération est encore nécessaire pour notre exemple : nous allons définir les colonnes en cliquant dans la propriété Columns. Nous ajoutons autant de colonnes que nous souhaitons et lions chaque colonne au champ qu'elle doit afficher. Ceci fait, on peut sélectionner toutes les colonnes pour aller cocher globalement l'option Title.Header. Ceci aura pour effet de lui demander de générer des balises ‘th' et non pas ‘td' pour la ligne de titres.

Voilà, exécutons notre application, et ce coup-ci notre grid est bien restylée :

Voilà, nous avons vu que tous les standards du web s'appliquent très bien et nous pouvons parfaitement, notamment grâce aux templates et aux CSS, sous-traiter la partie design de nos applications à des graphistes.

XIII - Utiliser les frames

La notion de frame est bien connue des Delphinautes. Dans le monde VCL, il s'agit de morceaux de formulaires non autonomes qui permettent de regrouper des éléments réutilisables. C'est bien de cette même notion qu'il s'agit dans Intraweb.

XIV - Création d'un frame

Pour créer un nouveau frame, il faut aller dans « Nouveaux éléments », onglet Intraweb, et choisir « New Frame » :

Intraweb nous crée une nouvelle unité, assortie d'un DFM. La classe générée hérite d'un TIWFrame, et elle agrège déjà un composant de type TIWRegion qui va être le conteneur de tous les composants de notre frame. En HTML ce composant va être traduit par une balise div. Parmi ses propriétés, on peut remarquer qu'il possède sa propre propriété « LayoutMgr ». Il peut donc utiliser son propre template HTML.

Une autre propriété est intéressante, il s'agit de « ClipRegion ». Si celle-ci est cochée, alors les composants resteront dans l'espace occupé par la région, et s'ils sont trop grands, alors des ascenseurs apparaîtront sur les bords de la région pour permettre de défiler l'écran. Si elle n'est pas cochée, alors la région ne limitera pas la place occupée par les composants.

XIV-A - Utilisation d'un frame

L'utilisation d'un frame va se faire de la même manière qu'en VCL, en utilisant le composant « Cadres » de la palette de composants « Standard ». Comme pour la VCL, on dépose le frame où on le souhaite dans le formulaire, il arrive avec l'ensemble de ses composants ainsi que leur comportement associé.

Si le formulaire met en œuvre un template, il faudra bien penser à placer un tag avec le nom du frame, sans quoi il n'apparaîtra pas (et donc aucun de ses composants). L'affichage est global pour le frame. Si nous souhaitons masquer par template des composants situés à l'intérieur du frame, il faut le faire via un template propre au frame, comme vu dans le paragraphe précédent.

XV - Les appels asynchrones

Une des évolutions qui a réussi à rendre les sites Internet plus conviviaux est certainement la possibilité d'effectuer des appels serveurs de façon transparente, permettant, à l'aide de JavaScript de modifier le contenu d'une page sans avoir à la rafraîchir intégralement, comme c'était le cas au début. Ce principe permet d'approcher la page web d'une application native.

On ne pourrait plus imaginer aujourd'hui un framework qui ne permettrait pas de bénéficier de cette avancée. Et bien entendu Intraweb n'échappe pas à la règle puisqu'il propose dans ses dernières versions d'effectuer des appels asynchrones au serveur. Ceci va se faire le plus simplement du monde à l'aide des événements des composants. De la même façon que nous avons sur un bouton (par exemple) un événement OnClick qui va poster le formulaire lorsque l'utilisateur va appuyer sur le bouton, nous disposons dans la liste des événements possibles d'un « OnAsyncClick » qui va se déclencher au même moment, mais qui au lieu de poster le formulaire va faire un appel asynchrone à la méthode associée. Et d'une manière générale, tous les composants possèdent des événements préfixés de « OnAsync » qui sont des appels asynchrones provoqués par l'événement lié.

Côté code, la méthode va recevoir deux paramètres :

- le classique paramètre Sender de type TObject qui contient la référence de l'instance du composant ayant provoqué l'appel ;

- un paramètre EventParams de type TStringlist qui va recevoir une liste de clés-valeurs contextuelles à l'événement et va nous permettre de récupérer un certain nombre d'informations (par exemple la position de la souris, le n° de la session…).

On va pouvoir ici aller lire du contenu en base de données afin de le retourner, et on va donc pouvoir agir dynamiquement sur la page déjà affichée. Deux remarques cependant :

- il est bien entendu possible de rendre visible un composant qui ne l'était pas. Par contre si le composant n'était pas visible au moment de l'affichage de la page, il faut bien penser à rendre active la propriété « RenderInvisibleControls » de l'objet TIWForm. Si cette propriété n'est pas à true, Intraweb ne génère pas le code du composant non visible lors de la génération de la page, ceci dans un souci d'optimisation. Par conséquent, ce composant ne pourra pas être rendu visible via un événement asynchrone étant donné que la page ne sera pas rechargée et celui-ci ne sera pas connu du DOM. Vous obtiendrez alors une erreur JavaScript tout à fait logique. Si cette propriété est active, alors le composant sera généré avec l'option non visible ;

- un appel asynchrone est très confortable pour l'utilisateur, mais cela reste un appel au serveur, qui va donc générer un peu de trafic réseau et un peu de charge serveur. Il faut donc se restreindre à utiliser cette possibilité si nous avons besoin d'agir en fonction d'éléments accessibles uniquement côté serveur (besoin de lire une information en base de données par exemple. Dans le cas contraire, il vaut mieux utiliser un JavaScript côté client. Nous allons voir comment faire cela.

XVI - Utilisation de JavaScript

Si nous voulons dynamiser nos applications web et apporter une expérience plus riche à l'utilisateur, le seul moyen est d'utiliser le JavaScript, le Pascal n'étant (malheureusement pour les Delphinautes) pas reconnu par les navigateurs.

Excepté le langage différent, l'utilisation du JavaScript dans Intraweb est aussi simple que pour les méthodes serveur. En effet, chaque composant visuel possède une propriété ScriptEvent permettant de coder les actions en JavaScript.

XVI-A - Coder un événement en JavaScript

Le but ici n'est pas d'apprendre le JavaScript, il y a d'excellents tutoriels sur ce site pour cela. Nous allons simplement voir comment inclure facilement un peu de code JavaScript pour exécuter des actions côté client.

Pour notre premier exemple, nous allons décider que l'utilisateur ne pourra lancer la recherche qu'à partir du moment où il aura saisi au moins trois caractères dans la zone de recherche. Ce script devra donc s'exécuter après chaque modification de la zone de saisie.

Sélectionnons le champ de recherche :

Et allons voir sa propriété ScriptEvents dans l'inspecteur de propriétés :

Un clic sur le petit bouton « … » fait apparaître une nouvelle fenêtre qui nous montre tous les événements possibles :

Il suffit de choisir celui qui nous intéresse. Dans notre cas nous allons sélectionner l'événement onKeyUp. Ceci fait, il suffit alors de saisir le code JavaScript dans la fenêtre de droite, comme ceci :

J'avais nommé mon composant iwdt1, Intraweb l'a généré donc avec un ID = IWDT1. Il met donc tous les noms en majuscules, ce qui est finalement une bonne chose, JavaScript étant case-sensitive, cela évite bien des erreurs. En cas de doute, il suffit de toute façon d'afficher le code source de la page générée et de rechercher notre élément pour voir son ID. Je passe donc sur la syntaxe du JavaScript.

Il ne faudra pas oublier d'initialiser la propriété enabled du bouton à false. Ceci peut se faire simplement dans l'IDE en désactivant la propriété enabled.

Il est également possible d'affecter le JavaScript par code et non pas par l'éditeur de script. Nous pourrions par exemple rajouter cela dans le constructeur de notre formulaire :

procedure TIWForm1.IWAppFormCreate(Sender: TObject);
begin
iwdt1.ScriptEvents.Values[ 'onKeyUp'] := 'if ( document.getElementById( "IWDT1").value.length > 3) {' +
'  document.getElementById( "BTN1").disabled=false;' +
'}' +
'else {' +
'  document.getElementById( "BTN1").disabled=true;' +
'}';
end;

XVI-B - Écriture de code JavaScript plus volumineux

En JavaScript, comme dans tous les langages, on va souvent capitaliser le travail en créant des méthodes ou des objets. On ne va bien entendu pas tout coder dans les événements et nous allons essayer d'appliquer nos bonnes méthodes de Delphinautes au JavaScript.

Pour cela, chaque formulaire Intraweb dispose d'une propriété JavaScript qui permet de saisir un code JavaScript. Cette propriété est de type TStrings, donc comme pour les événements, on peut soit taper directement le code dans l'éditeur de propriété, soit l'affecter dans notre code, soit encore le charger dynamiquement depuis un fichier texte qui regrouperait toutes nos méthodes JavaScript.

XVI-C - Paramètres pour le JavaScript au niveau de l'application

Enfin, dans l'unité ServerController, l'objet TIWServerController dispose d'une propriété permettant de régler quelques paramètres concernant l'usage du JavaScript :

- AjaxErrorMode : permet de déterminer comment les messages d'erreur seront affichés. Nous avons le choix entre :

- emAlert (mode par défaut) : classiquement une fenêtre d'alerte s'affiche à l'utilisateur,

- emConsole : consigne le message dans la console accessible en mode débogage des navigateurs,

- emNone : le message n'est pas émis ;

- Debug : autorise ou non le débogage JavaScript ;

- EnabledFirebug : permet l'utilisation de l'outil de débogage du navigateur Firefox ;

- UseUncompressedFiles : par défaut tous les fichiers JavaScript sont envoyés compressés, pour des raisons évidentes d'optimisation de bande passante. On peut cependant demander à Intraweb de les envoyer sans compression, pour des raisons de débogage ou parce que parmi les clients de notre application, certains ne disposent pas d'un navigateur acceptant les flux compressés.

XVII - Annexes

XVII-A - Les principales propriétés de la classe TIWServerController

XVII-A-1 - AllowMultipleSessionPerUser

Cette propriété va permettre de déterminer sous quelle forme le numéro de la session de l'utilisateur va être géré. C'est un champ boolean qui peut donc prendre deux états :

- false : c'est la valeur par défaut. Dans ce cas, le numéro de session est géré par un cookie et sera donc le même, quel que soit l'onglet ou même le navigateur du client. Il ne peut donc y avoir qu'une seule session par client ;

- true : dans ce cas le numéro de session est passé via l'URL. Il y aura autant de n° de sessions générés que d'onglets ou de navigateurs ouverts par l'utilisateur, qui peut donc ouvrir plusieurs sessions depuis son poste.

XVII-A-2 - AppName

Cette propriété permet d'indiquer le nom de l'application. Il apparaîtra dans les messages par défaut d'Intraweb lors d'une exception ou d'une fin de session. Ce sera également ce nom qui sera donné au service Windows si nous installons le service en tant que service Windows.

XVII-A-3 - AuthBeforeNewSession

Cette propriété n'est effective que si elle est conjuguée avec la propriété Auther. Elle va permettre simplement de préciser si la session doit d'abord être créée avant l'authentification de l'utilisateur, ou seulement s'il est authentifié.

- Si false, alors on crée la session, puis l'utilisateur peut s'authentifier. Si l'authentification échoue, alors la session est supprimée.

- Si true, alors l'utilisateur s'authentifie et si l'authentification aboutit, alors la session est créée.

XVII-A-4 - Auther

Cette propriété permet d'associer un composant descendant de TIWAutherBase. Trois sont fournis en standard :

- TIWAutherList : permet d'identifier l'utilisateur à partir d'une liste fournie dans un Tstrings ;

- TIWAutherIni : permet d'identifier l'utilisateur à partir d'un fichier ini ;

- TIwAutherEvent : fournit un événement avec les informations d'authentification et nous laisse gérer l'identification de l'utilisateur.

XVII-A-5 - BackButtonOptions

Avec cette propriété on va définir la façon de gérer l'appui sur le bouton « Précédent » du navigateur. Depuis le début d'Intraweb, on peut afficher un message lorsque l'utilisateur clique sur précédent. Avec les dernières versions, Atozed permet d'affiner cet affichage à l'aide de la propriété « Mode » qui peut prendre comme valeur :

- bmInterceptGlobal : l'appui sera intercepté globalement sur toute l'application ;

- bmInterceptForm : l'appui sera intercepté sur les formulaires pour lesquels on aura positionné la propriété « PreventBackButton » à true (et seulement ceux-ci) ;

- bmEnable : aucune interception, l'utilisateur pourra donc utiliser la fonction « Précédent » (attention dans ce cas à bien la gérer) ;

- bmDisableCompat : fonctionnement identique aux anciennes versions (message d'avertissement).

La propriété Showmessage permet d'indiquer si on veut un message, ce message pouvant être personnalisé à l'aide de la propriété « WarningMessage ».

XVII-A-6 - BoundIP

Permet d'indiquer à quelle adresse IP l'application va répondre dans le cas où le serveur sur lequel elle est installée dispose de plusieurs cartes réseau.

XVII-A-7 - CacheDir

Permet de spécifier le répertoire dont Intraweb va se servir pour stocker les éléments qu'il met en cache.

XVII-A-8 - ComInitialization

Cette propriété permet de demander à Intraweb d'appeler les routines d'initialisation des objets COM. Cela est utile notamment lorsque l'application a besoin d'utiliser des connexions ADO.

XVII-A-9 - Compression

Permet d'activer ou désactiver la compression du flux, certains navigateurs n'acceptant pas forcément de recevoir du flux compressé.

XVII-A-10 - Description

Ici on peut inscrire le texte qui apparaîtra en description de service si notre application est installée comme service Windows.

XVII-A-11 - DisplayName

Contient le nom de l'application tel qu'il apparaîtra dans le gestionnaire de services Windows si notre application est installée en tant que service.

XVII-A-12 - Port

Permet de modifier le port d'écoute de l'application, dans le cas où on utilise le serveur web intégré. Par défaut il est positionné sur le port 8888.

XVII-A-13 - SessionTimeout

Indique la période d'inactivité maximale après laquelle Intraweb terminera la session. Cette période est exprimée en minutes.

XVII-A-14 - StyleSheet

C'est ici qu'on va pouvoir indiquer la feuille de style à utiliser pour notre application. Elle peut être indiquée sous forme d'URL, ou bien on peut préciser le nom du fichier, ce dernier devant alors se placer dans le répertoire wwwRoot.

XVII-A-15 - TemplateDir

Ici on peut indiquer le chemin du répertoire contenant les templates HTML, si ce dernier est différent du chemin par défaut, c'est-à-dire \Templates.

XVII-B - Les événements de la classe TIWServerController

XVII-B-1 - OnNewSession

Cet événement est implémenté par défaut par le Framework, il s'agit de la méthode appelée lors de la connexion d'un nouvel utilisateur. C'est donc ici qu'Intraweb va créer le Datamodule qui va servir à stocker les éléments de la session. C'est ici aussi, comme on le verra plus bas, qu'on va pouvoir influer sur la page de démarrage de l'application Web.

XVII-B-2 - OnException

Cet événement est appelé lorsqu'une exception est levée. Il va permettre de préciser si on la traite ou non à l'aide du paramètre variable Handle. Un objet de type Exception est également transmis pour avoir les détails de l'exception.

XVII-B-3 - OnLogException

Appelé comme le précédent, il contient le log relatif à l'exception dans un paramètre de type TStrings.

XVIII - Remerciements

Je remercie Papy214 pour sa relecture technique et pour ses tests, ainsi que FRANOUCH et Claude LELOUP pour leur relecture orthographique.