Réécriture d'URL dans ASP.NET

Scott Mitchell
4GuysFromRolla.com

S'applique à :
   Microsoft® ASP.NET

Résumé : Explique comment réécrire des URL dynamiques dans Microsoft ASP.NET. La réécriture d'URL consiste à intercepter une requête Web entrante et à la rediriger automatiquement vers une autre URL. Explique les diverses techniques d'implémentation de la réécriture d'URL et analyse des scénarios réels de réécriture d'URL.

Téléchargez le code source de cet article.

Sommaire

Introduction
Utilisations courantes de la réécriture d'URL
Que se passe-t-il lorsqu'une requête atteint IIS
Implémentation de la réécriture d'URL
Création d'un moteur de réécriture d'URL
Réécriture d'URL simple avec le moteur de réécriture d'URL
Création d'URL vraiment « abrégeable »
Conclusion
Bibliographie

Introduction

Arrêtez-vous quelques instants pour examiner les URL de votre site Web. Trouvez-vous des URL de type http://votresite.com/info/dispEmployeeInfo.aspx?EmpID=459-099&type=summary ? Ou vous disposez peut-être d'un groupe de pages Web qui ont été transférées d'un répertoire ou d'un site Web vers un autre provoquant des ruptures de liens pour les visiteurs qui ont enregistré les anciennes URL dans un signet. Cet article porte sur l'utilisation de la réécriture d'URL en vue de raccourcir ces affreuses URL pour disposer d'URL significatives mémorisables en remplaçant http://votresite.com/info/dispEmployeeInfo.aspx?EmpID=459-099&type=summary par quelque chose du type http://yoursite.com/people/sales/chuck.smith. Nous verrons comment il est possible d'utiliser la réécriture d'URL pour créer une erreur 404 intelligente.

La réécriture d'URL consiste à intercepter une requête Web entrante et à la rediriger vers une autre ressource. Lors de la réécriture d'URL, l'URL demandée est généralement vérifiée et redirigée vers une autre URL en fonction de sa valeur. Lorsque, dans le cadre de la restructuration d'un site Web, par exemple, toutes les pages du répertoire /people/ doivent être transférées vers le répertoire /info/employees/, vous utiliserez la réécriture d'URL pour vérifier si une demande Web était associée à un fichier du répertoire /people/. Si tel est le cas, vous ne voulez pas rediriger la demande vers le même fichier, mais dans le répertoire /info/employees/.

Avec ASP classique, la seule manière d'utiliser la réécriture d'URL consistait à écrite un filtre ISAPI ou à acheter un produit tiers offrant des fonctions de réécriture d'URL. Toutefois, avec Microsoft® ASP.NET, vous pouvez créer aisément votre propre programme de réécriture d'URL de différentes manières. Dans cet article, nous allons examiner les techniques dont disposent les développeurs ASP.NET pour implémenter la réécriture d'URL et utiliser des applications réelles de réécriture d'URL. Avant de nous plonger dans les spécificités technologiques de la réécriture d'URL, examinons quelques scénarios quotidiens dans lesquels la réécriture d'URL peut être utilisée.

Utilisations courantes de la réécriture d'URL

La création de sites Web ASP.NET reposant sur les données génère souvent une seule page Web qui affiche un sous-ensemble des données de la base de données en fonction de paramètres de chaîne d'interrogation. Par exemple, lors de la conception d'un site e-commerce, une de vos tâches consiste à permettre aux utilisateurs de naviguer dans les produits en vente. Pour faciliter cette opération, vous pouvez créer une page displayCategory.aspx qui affiche les produits d'une catégorie donnée. Les produits de la catégorie à afficher sont définis par un paramètre de chaîne de requête, c'est-à-dire que si l'utilisateur veut naviguer dans les articles en vente et que tous les articles ont un ID de catégorie (CategoryID) 5, l'utilisateur visite : http://votresite.com/displayCategory.aspx?CategoryID=5.

La création d'un site Web avec des URL de ce type a deux inconvénients. Tout d'abord, pour l'utilisateur, l'URL http://votresite.com/displayCategory.aspx?CategoryID=5 est incompréhensible. L'expert en utilisation, Jakob Neilsen recommande Lien externe au site MSDN France Site en anglais de choisir des URL :

  • courtes ;
  • faciles à taper ;
  • qui affichent la structure du site ;
  • qui soient « abrégeables » pour permettre à l'utilisateur de naviguer sur le site en supprimant des parties de l'URL.

J'ajouterai que les URL doivent être faciles à retenir. L'URL http://votresite.com/displayCategory.aspx?CategoryID=5 ne répond à aucun des critères de Neilsen et elle n'est pas non plus facile à mémoriser. Demander aux utilisateurs de taper des valeurs de chaînes de requête ne facilite pas la saisie d'une URL et ne la rend « abrégeable » que par les développeurs Web expérimentés qui connaissent la fonction des paramètres de chaîne d'interrogation et leur structure de paire nom/valeur.

Une meilleure approche consiste à utiliser une URL compréhensible mémorisable telle que http://votresite.com/products/Widgets. En lisant simplement l'URL vous pouvez déterminer ce qui va s'afficher : des informations sur les articles. L'URL est aisément mémorisable et partageable également. Je peux dire à mon collègue d'aller sur le site votresite.com/products/Widgets sans qu'il ait besoin de me redemander l'URL pour afficher la page. Essayez de faire ça avec une page Amazon.com ! L'URL apparaît également et doit être « abrégeable », c'est-à-dire que si l'utilisateur tronque la fin de l'URL et tape http://votresite.com/products, il doit pouvoir afficher la liste de tous les produits ou au moins la liste de toutes les catégories de produits qu'il peut afficher.

Remarque    Les URL générées par de nombreux moteurs de blog Web constituent un bon exemple d'URL abrégeable. Pour afficher les publications du 28 janvier 2004, vous visitez une URL de type http://blogquelconque.com/2004/01/28. Si l'URL est tronquée et correspond à http://blogquelconque.com/2004/01, l'utilisateur affiche tous les envois de janvier 2004 et si elle est tronquée davantage pour correspondre http://blogquelconque.com/2004, elle affiche tous les envois de l'année 2004.

Outre la simplification des URL, la réécriture d'URL est souvent utilisée pour gérer la restructuration de sites Web qui génèrerait autrement un grand nombre de ruptures de liens et de signets obsolètes.

Que se passe-t-il lorsqu'une requête atteint IIS ?

Avant d'examiner exactement la manière d'implémenter la réécriture d'URL, il est important de comprendre comment IIS Microsoft® (Internet Information Services) traite les demandes entrantes. Lorsqu'une requête arrive sur un serveur Web IIS, IIS examine l'extension du fichier demandé pour déterminer la manière de traiter la demande. Les demandes peuvent être traitées en natif par IIS (comme le sont les pages HTML, les images et les autres types de contenus statiques) ou IIS peut envoyer la requête à une extension ISAPI. Une extension ISAPI est une classe compilée non gérée qui traite une requête Web entrante. Elle a pour fonction de générer le contenu pour la ressource demandée.

Si, par exemple, la page Info.asp est demandée, IIS envoie le message à l'extension ISAPI asp.dll. Cette extension ISAPI charge alors la page ASP, l'exécute et retourne son rendu HTML à IIS qui l'envoie au client qui la demande. Pour les pages ASP.NET, IIS envoie le message à l'extension ISAPI aspnet_isapi.dll. Cette extension passe le traitement au processus de travail ASP.NET géré qui traite la demande en retournant le rendu HTML de la page Web ASP.NET.

Vous pouvez personnaliser IIS pour définir les extensions associées aux extensions ISAPI. La figure 1 montre la boîte de dialogue Configuration de l'application de l'outil Internet Information Services Administrative. Notez que les extensions ASP.NET (.aspx, .ascx, .config, .asmx, .rem, .cs, .vb, etc.) sont toutes mappées à l'extension ISAPI aspnet_isapi.dll ISAPI.

urlrewriting_fig01.gif

Figure 1. Mappages configurés pour les extensions de fichiers

Une présentation approfondie de la manière dont IIS gère les demandes entrantes n'entre pas tout à fait dans le cadre de cet article. Pour une présentation plus approfondie sur ce sujet, reportez-vous à l'article Inside IIS and ASP.NET Lien externe au site MSDN France Site en anglais de Michele Leroux Bustamante. Il est important de comprendre que le moteur ASP.NET ne traite que les demandes Web dont les extensions sont explicitement mappées à aspnet_isapi.dll dans IIS.

Analyse des demandes avec des filtres ISAPI

Outre l'association de l'extension de fichier de la demande Web à l'extension ISAPI appropriée, IIS exécute d'autres tâches. IIS, par exemple, tente d'authentifier l'utilisateur à l'origine de la demande et détermine si l'utilisateur authentifié est autorisé à accéder au fichier demandé. Au cours de la durée de vie de la gestion d'une requête, IIS passe par différents états. Pour chaque état, IIS déclenche un événement qui peut être géré par un programme en utilisant des filtres ISAPI.

À l'instar des extensions ISAPI, les filtres ISAPI sont des blocs de code non gérés installés sur le serveur Web. Les extensions ISAPI sont conçues pour générer la réponse à une demande de type de fichier particulier. En revanche, les filtres ISAPI contiennent du code pour répondre aux événements déclenchés par IIS. Les filtres ISAPI peuvent intercepter et même modifier les données entrantes et sortantes. Les filtres ISAPI ont une multitude d'applications, notamment :

  • authentification et autorisation ;
  • journalisation et surveillance ;
  • compression HTTP ;
  • réécriture d'URL.

Bien que des filtres ISAPI puissent être utilisés pour effectuer des opérations de réécriture d'URL, cet article porte sur l'implémentation de la réécriture d'URL à l'aide de ASP.NET. Toutefois, nous aborderons les compromis entre l'implémentation de la réécriture d'URL sous la forme d'un filtre ISAPI et l'utilisation des techniques disponibles dans ASP.NET.

Que se passe-t-il lorsqu'une demande entre dans le moteur ASP.NET ?

Avant ASP.NET, la réécriture d'URL sur les serveurs Web IIS devait être implémentée à l'aide d'un filtre ISAPI. La réécriture d'URL avec ASP.NET est possible, car le moteur ASP.NET est étonnamment similaire à IIS. Cette similarité existe parce que le moteur ASP.NET :

  1. déclenche des événements lorsqu'il traite une demande ;
  2. permet à un nombre arbitraire de modules HTTP de gérer les événements déclenchés, comme les filtres ISAPO de IIS ;
  3. délègue le rendu de la ressource demandée à un gestionnaire HTTP semblable aux extensions SAPI d'IIS.

À l'instar d'IIS, au cours de la durée de vie d'une demande, le moteur ASP.NET déclenche des événements pour signaler qu'il change d'état. L'événement BeginRequest, par exemple, est déclenché lorsque le moteur ASP.NET répond pour la première fois à une demande. L'événement AuthenticateRequest est déclenché ensuite et se produit lorsque l'identité de l'utilisateur est établie. (Il existe beaucoup d'autres événements : AuthorizeRequest, ResolveRequestCache et EndRequest, entre autres. Ces événements sont des événements de la classe System.Web.HttpApplication. Pour plus d'informations, consultez la documentation technique HttpApplication Class Overview Lien externe au site MSDN France Site en anglais.)

Comme nous l'avons vu dans la section précédente, vous pouvez créer des filtres ISAPI pour répondre aux événements déclenchés par IIS. De la même manière, ASP.NET fournit des modules HTTP qui peuvent répondre aux événements déclenchés par le moteur ASP.NET. Il est possible de configurer une application Web ASP.NET pour disposer de plusieurs modules HTTP. Pour chaque demande traitée par le moteur ASP.NET, chaque module HTTP configuré est initialisé et autorisé à lier des gestionnaires d'événements aux événements déclenchés au cours du traitement de la demande. Sachez qu'un certain nombre de modules HTTP incorporés est utilisé dans chaque demande. L'un des modules HTTP incorporés est FormsAuthenticationModule ; il vérifie en premier lieu si des formulaires d'authentification sont utilisés et, dans ce cas, si l'utilisateur a été authentifié ou non. Si tel n'est pas le cas, l'utilisateur est renvoyé directement vers la page d'ouverture de session définie.

Rappelez-vous qu'avec IIS une demande entrante est redirigée vers une extension ISAPI dont la fonction consiste à retourner les données de la demande. Par exemple, lorsqu'une demande de page WEB ASP classique arrive, ISS remet la demande à l'extension ISAPI asp.dll qui doit retourner le code HTML de la page ASP demandée. Le moteur ASP.NET utilise une approche similaire. Après avoir initialisé les modules HTTP, le moteur ASP.NET doit déterminer le gestionnaire HTTP qui doit traiter la demande.

Toutes les demandes qui passent par le moteur ASP.NET sont réceptionnées par un gestionnaire HTTP ou une fabrique (factory, en anglais) de gestionnaires HTTP (une fabrique de gestionnaires HTTP retourne simplement une instance d'un gestionnaire HTTP utilisée pour traiter la demande). Le dernier gestionnaire HTTP fournit la ressource demandée en retournant la réponse. La réponse est renvoyée à IIS qui la renvoie à l'utilisateur à l'origine de la demande.

ASP.NET inclut un certain nombre de gestionnaires HTTP incorporés. Le gestionnaire PageHandlerFactory, par exemple, est utilisé pour le rendu des pages Web ASP.NET. Le gestionnaire WebServiceHandlerFactory est utilisé pour le rendu des enveloppes SOAP de réponse pour les services Web ASP.NET. Le gestionnaire TraceHandler fournit le rendu du code HTML des demandes à trace.axd.

La figure 2 montre le traitement d'une demande de ressource ASP.NET. En premier lieu, ISS reçoit la demande et l'envoie à aspnet_isapi.dll. Le moteur ASP.NET initialise ensuite les modules HTTP configurés. Enfin, le gestionnaire HTTP approprié est appelé et la ressource demandée est rendue en retournant le code généré à ISS et au client demandeur.

urlrewriting_fig02.gif

Figure 2. Demande de traitement par IIS et ASP.NET

Création et enregistrement des modules et des gestionnaires HTTP personnalisés

La création de modules et de gestionnaires HTTP personnalisés est relativement simple ; elle implique de créer une classe gérée qui implémente l'interface appropriée. Les modules HTTP doivent implémenter l'interface System.Web.IHttpModule alors que les gestionnaires et HTTP et les fabriques de gestionnaires HTTP doivent implémenter respectivement l'interface System.Web.IHttpHandler et l'interface System.Web.IHttpHandlerFactory. La création de gestionnaires HTTP et de modules HTTP n'entre pas dans le cadre de cet article. Reportez-vous à l'article HTTP Handlers and HTTP Modules in ASP.NET Lien externe au site MSDN France Site en anglais de Mansoor Ahmed Siddiqui qui constitue une base solide.

Après avoir créé un module HTTP ou un gestionnaire HTTP personnalisé, vous devez l'enregistrer dans l'application Web. L'enregistrement des modules HTTP et des gestionnaires HTTP de l'ensemble d'un serveur Web implique un simple ajout au fichier machine.config ; l'enregistrement d'un module HTTP ou d'un gestionnaire HTTP pour une application Web implique d'ajouter quelques lignes de code XML au fichier Web.config de l'application.

Plus précisément, pour ajouter un module HTTP à une application Web, ajoutez les lignes suivantes dans la section configuration/system.web du fichier Web.config :

<httpModules>
 <add type="type" name="name" />
</httpModules>

La valeur type fournit l'assembly et le nom de classe du module, alors que la valeur name fournit un nom convivial qui peut être utilisé pour faire référence au module HTTP dans le fichier Global.asax.

Les gestionnaires HTTP et les fabriques de gestionnaires HTTP sont configurés par la balise <httpHandlers> dans la section configuration/system.web du fichier Web.config, comme suit :

<httpHandlers>
 <add verb="verb" path="path" type="type" />
</httpHandlers>

Souvenez-vous que pour chaque demande entrante, le moteur ASP.NET détermine le gestionnaire HTTP qui doit être utilisé pour le rendu de la demande. Cette décision dépend du verbe et du chemin de la demande entrante. Le verbe définit le type de la demande HTTP (GET ou POST), alors que le chemin spécifie l'emplacement et le nom du fichier demandé. Ainsi, si nous voulons qu'un gestionnaire HTTP traite toutes les demandes (GET ou POST) de fichiers avec l'extension .scott, nous devons ajouter les lignes suivantes dans le fichier Web.config :

<httpHandlers>
 <add verb="*" path="*.scott" type="type" />
</httpHandlers>

type correspond au type du gestionnaire HTTP.

Remarque    Lorsque vous enregistrer des gestionnaires HTTP, il est important de s'assurer que les extensions utilisées par le gestionnaire sont mappées au moteur ASP.NET dans IIS. Ainsi, dans le cas de l'exemple .scott , si l'extension .scott n'est pas associée à l'extension ISAPI aspnet_isapi.dll dans IIS, une demande du fichier foo.scott amène IIS à tenter de retourner le contenu du fichier foo.scott. Pour que le gestionnaire HTTP puisse traiter cette demande, l'extension .scott doit être associée au moteur ASP.NET. Le moteur ASP.NET envoie ensuite la demande correctement au gestionnaire HTTP approprié.

Pour plus d'informations sur l'enregistrement des modules HTTP et des gestionnaires HTTP, reportez-vous à la documentation de l'élément <httpModules> Lien externe au site MSDN France Site en anglais et à la http://msdn.microsoft.com/library/en-us/cpgenref/html/gngrfHttphandlersSection.asp documentation de l'élément <httpHandlers> Lien externe au site MSDN France Site en anglais.

Implémentation de la réécriture d'URL

La réécriture d'URL peut être implémentée avec des filtres ISAPI sur le serveur Web ISS ou avec des modules HTTP ou des gestionnaires HTTP au niveau ASP.NET. Cet article porte sur l'implémentation de la réécriture d'URL avec ASP.NET. Nous n'aborderons donc pas l'implémentation d'URL à l'aide de filtres ISAPI.

Il est possible d'implémenter la réécriture d'URL au niveau ASP.NET via la méthode RewritePath() de la classe System.Web.HttpContext. La classe HttpContext contient des informations HTTP sur une demande HTTP donnée. Pour chaque demande que reçoit le moteur ASP.NET, une instance HttpContext est créée pour la demande. Cette classe a des propriétés de type : Request et Response qui permettent d'accéder à la demande entrante et à la réponse sortante, Application et Session qui permettent d'accéder aux variables de l'application et de la session, User qui fournit des informations sur l'utilisateur authentifié, et d'autres propriétés associées.

Avec Microsoft® .NET Framework Version 1.0, la méthode RewritePath() accepte une seule chaîne, le nouveau chemin à utiliser. En interne, la méthode RewritePath(string) de la classe HttpContext met à jour les propriétés Path et QueryString de l'objet Request. Outre RewritePath(string), .NET Framework Version 1.1 contient une autre forme de la méthode RewritePath(), qui accepte trois paramètres d'entrée de chaîne. Cette forme alternative définit non seulement les propriétés Path et QueryString de l'objet Request, mais également les variables des membres internes utilisés pour calculer les valeurs PhysicalPath, PathInfo et FilePath de l'objet Request.

Pour implémenter la réécriture d'URL dans ASP.NET, il est nécessaire de créer un module HTTP ou un gestionnaire HTTP qui :

  1. vérifie le chemin demandé pour déterminer si l'URL doit être réécrite ;
  2. réécrit le chemin, si nécessaire, en appelant la méthode RewritePath().

Imaginons que le site Web contenait des informations sur chaque employé, accessibles via /info/employee.aspx?empID=employeeID. Pour rendre ces URL plus « abrégeables », nous pouvons décider de rendre les pages des employés accessibles à l'aide de : /people/EmployeeName.aspx. Il s'agit d'un cas où nous voulons utiliser la réécriture d'URL, c'est-à-dire, quand la page /people/ScottMitchell.aspx est demandée, nous voulons réécrire l'URL pour utiliser en fait la page /info/employee.aspx?empID=1001.

Réécriture d'URL avec des modules HTTP

Pour exécuter la réécriture d'URL au niveau ASP.NET, vous pouvez utiliser un module HTTP ou un gestionnaire HTTP. Lorsque vous utilisez un module HTTP, vous devez déterminer au cours du cycle de vie de la demande le moment où il est nécessaire de vérifier si l'URL doit être réécrite. À priori, cela peut paraître un choix arbitraire, mais la décision peut affecter l'application de manière significative et subtile. Le choix du moment de la réécriture est important, car les modules HTTP ASP.NET incorporés utilisent les propriétés de l'objet Request pour exécuter leurs tâches. (Souvenez-vous que la réécriture du chemin modifie les valeurs des propriétés de l'objet Request.) Ces modules HTTP incorporés et les événements auxquels ils s'intègrent sont énumérés ci-dessous :

Module HTTP Événement Description
FormsAuthenticationModule AuthenticateRequest Détermine si l'utilisateur est authentifié en utilisant des formulaires d'authentification. Si tel n'est pas le cas, l'utilisateur est renvoyé directement vers la page d'ouverture de session définie.
FileAuthorizationModule AuthorizeRequest Lorsque vous utilisez l'authentification Windows, ce module HTTP vérifie si le compte Microsoft® Windows® dispose des droits appropriés sur la ressource demandée.
UrlAuthorizationModule AuthorizeRequest Vérifie si le demandeur peut accéder à l'URL spécifiée. L'autorisation d'URL est définie via les éléments <authorization> et <location> dans le fichier Web.config.

Souvenez-vous que l'événement BeginRequest se déclenche avant AuthenticateRequest qui se déclenche avant AuthorizeRequest.

L'événement BeginRequest constitue un emplacement adéquat pour exécuter la réécriture d'URL. Cela implique que si l'URL doit être réécrite, elle le sera avant que l'un des modules HTTP incorporés s'exécute. Mais cette approche a un inconvénient lorsque des formulaires d'authentification sont utilisés. Si vous avez déjà utilisé des formulaires d'authentification, vous savez que lorsqu'un utilisateur visite une ressource restreinte, il est redirigé automatiquement vers une page d'ouverture de session définie. Une fois connecté, l'utilisateur est renvoyé vers la page à laquelle il a tenté d'accéder en premier lieu.

Si la réécriture d'URL est exécutée dans l'événement BeginRequest ou AuthenticateRequest, la page d'ouverture de session, lorsqu'elle est resoumise, renvoie l'utilisateur avec la page réécrite. Imaginons, qu'un utilisateur tape, dans son navigateur, /people/ScottMitchell.aspx qui est réécrit en /info/employee.aspx?empID=1001. Si l'application Web est configurée pour utiliser des formulaires d'authentification, l'utilisateur visite d'abord /people/ScottMitchell.aspx, l'URL est réécrite en /info/employee.aspx?empID=1001, puis FormsAuthenticationModule s'exécute pour renvoyer l'utilisateur vers la page d'ouverture de session, si nécessaire. Toutefois, l'URL vers laquelle l'utilisateur est renvoyé après avoir ouvert une session sera /info/employee.aspx?empID=1001 du fait qu'il s'agissait de l'URL de la demande au moment de l'exécution de FormsAuthenticationModule.

De même, lorsque vous exécutez la réécriture dans l'événement BeginRequest ou AuthenticateRequest, UrlAuthorizationModule voit l'URL réécrite. Cela implique que si vous utilisez des éléments <location> dans le fichier Web.config pour définir les autorisations d'URL spécifiques, vous devez faire référence à l'URL réécrite.

Pour résoudre ces subtilités, vous pouvez décider d'exécuter la réécriture d'URL dans l'événement AuthorizeRequest. Bien que cette approche résolve les anomalies d'autorisation d'URL et de formulaires d'authentification, elle introduit un nouveau problème : les autorisations de fichier ne fonctionnent plus. Lorsque vous utilisez l'authentification Windows, FileAuthorizationModule vérifie si l'utilisateur authentifié dispose des droits d'accès appropriés à la page ASP.NET.

Supposons que des utilisateurs ne disposent pas d'un accès fichier au niveau Windows sur C:\Inetput\wwwroot\info\employee.aspx et qu'ils tentent d'accéder à /info/employee.aspx?empID=1001. Dans ce cas, ils reçoivent une erreur d'autorisation. Toutefois, si nous transférons la réécriture d'URL vers l'événement AuthenticateRequest, lorsque FileAuthorizationModule vérifie les paramètres de sécurité, il considère toujours que le fichier demandé est /people/ScottMitchell.aspx du fait que l'URL n'a pas encore été réécrite. En conséquence, la vérification d'autorisation de fichier est transmise pour permettre à l'utilisateur de voir le contenu de l'URL réécrite, /info/employee.aspx?empID=1001.

Alors, quand est-il nécessaire de réécrire une URL dans un module HTTP ? Cela dépend du type d'authentification que vous utilisez. Si vous n'utilisez pas d'authentification, peu importe si l'URL est réécrite dans BeginRequest, AuthenticateRequest ou AuthorizeRequest. Si vous utilisez des formulaires d'authentification et n'utilisez pas l'authentification Windows, exécutez la réécriture d'URL dans la gestion d'événements AuthorizeRequest. Enfin, si vous utilisez l'authentification Windows, planifiez la réécriture d'URL au cours des événements BeginRequest ou AuthenticateRequest.

Réécriture d'URL dans les gestionnaires HTTP

La réécriture d'URL peut être également exécutée par un gestionnaire HTTP ou une fabrique de gestionnaires HTTP. Notez qu'un gestionnaire HTTP est une classe chargée de générer le contenu d'un type de demande spécifique. Une fabrique de gestionnaires HTTP est une classe chargée de retourner une instance d'un gestionnaire HTTP qui peut générer le contenu d'un type de demande spécifique.

Dans cet article, nous allons aborder la création d'une fabrique de gestionnaires HTTP de réécriture d'URL pour des pages Web ASP.NET. Les fabriques de gestionnaires HTTP doivent implémenter l'interface IHttpHandlerFactory qui inclut une méthode GetHandler(). Après avoir initialisé les modules HTTP appropriés, le moteur ASP.NET détermine le gestionnaire HTTP ou la fabrique de gestionnaires HTTP à appeler pour une demande donnée. Si une fabrique de gestionnaires HTTP doit être appelée, le moteur ASP.NET appelle la méthode GetHandler() de la fabrique de gestionnaires HTTP pour passer l'objet HttpContext de la demande Web avec d'autres informations. La fabrique de gestionnaires HTTP doit ensuite retourner un objet qui implémente le IHttpHandler qui peut traiter la demande.

Pour exécuter la réécriture d'URL via un gestionnaire HTTP, nous pouvons créer une fabrique de gestionnaires HTTP dont la méthode GetHandler() vérifie le chemin demandé pour déterminer s'il doit être réécrit. S'il doit l'être, il peut appeler la méthode RewritePath() transmise de l'objet HttpContext, comme nous l'avons vu précédemment. Enfin, la fabrique de gestionnaires HTTP peut retourner le gestionnaire HTTP retourné par la méthode GetCompiledPageInstance() de la classe System.Web.UI.PageParser. (la fabrique de gestionnaires HTTP de page Web ASP.NET incorporée PageHandlerFactory fonctionne selon le même principe).

Du fait que tous les modules HTTP sont initialisés avant la fabrique de gestionnaires HTTP personnalisée à instancier, l'utilisation d'une fabrique de gestionnaires HTTP présente les mêmes inconvénients que de placer la réécriture d'URL dans les dernières étapes des événements, c'est-à-dire que les autorisations de fichier ne fonctionnent pas. En conséquence, si vous utilisez l'authentification Windows et l'autorisation de fichier, utilisez le module HTTP pour réécrire les URL.

La section suivante porte sur la création d'un moteur de réécriture d'URL réutilisable. Après l'analyse du moteur de réécriture d'URL, disponible en téléchargeant cet article, nous consacrerons deux sections à analyser des utilisations réelles de la réécriture d'URL. Tout d'abord nous allons apprendre à utiliser le moteur de réécriture d'URL et étudier un exemple simple de réécriture d'URL. Ensuite, nous utiliserons la puissance des expressions régulières du moteur de réécriture pour fournir des URL véritablement « abrégeables ».

Création d'un moteur de réécriture d'URL

Pour illustrer la manière d'implémenter la réécriture d'URL dans une application Web ASP.NET, j'ai créé un moteur de réécriture d'URL. Ce moteur de réécriture fournir la fonctionnalité suivante :

  • Le développeur de pages ASP.NET qui utilise le moteur de réécriture d'URL peut définir les règles de réécriture dans le fichier Web.config.
  • Les règles de réécriture peuvent utiliser des expressions régulières pour disposer de règles de réécriture puissantes.
  • La réécriture d'URL peut être aisément configurée pour utiliser un module HTTP ou un gestionnaire HTTP.

Dans cet article, nous allons examiner la réécriture d'URL avec le module HTTP uniquement. Pour savoir comment les gestionnaires HTTP peuvent être utilisés pour la réécriture d'URL, consultez le code téléchargeable avec cet article.

Définition des informations de configuration du moteur de réécriture d'URL

Examinons la structure des règles de réécriture dans le fichier Web.config. Tout d'abord, vous devez indiquer dans le fichier Web.config si vous voulez exécuter la réécriture d'URL avec le module HTTP ou le gestionnaire HTTP. Dans la version téléchargeable, le fichier Web.config contient deux entrées mises en commentaire :

<!--
<httpModules>
 <add type="URLRewriter.ModuleRewriter, URLRewriter" 
 name="ModuleRewriter" />
</httpModules>
-->

<!--
<httpHandlers>
 <add verb="*" path="*.aspx" 
 type="URLRewriter.RewriterFactoryHandler, URLRewriter" />
</httpHandlers>
-->

Mettez en commentaire l'entrée <httpModules> pour utiliser le module HTTP pour la réécriture. Mettez en commentaire l'entrée <httpHandlers> pour utiliser le gestionnaire HTTP pour la réécriture.

Le fichier Web.config permet d'indiquer si vous voulez utiliser le module HTTP ou le gestionnaire HTTP et contient également des règles de réécriture. Une règle de réécriture est constituée de deux chaînes : le modèle à rechercher dans l'URL demandée et la chaîne de remplacement du modèle, s'il existe. Ces informations sont exprimées selon la syntaxe suivante dans le fichier Web.config :

<RewriterConfig>
 <Rules>
 <RewriterRule>
 <LookFor>pattern to look for</LookFor>
 <SendTo>string to replace pattern with</SendTo>
 </RewriterRule>
 <RewriterRule>
 <LookFor>pattern to look for</LookFor>
 <SendTo>string to replace pattern with</SendTo>
 </RewriterRule>
 ...
 </Rules>
</RewriterConfig>

Chaque règle de réécriture est exprimée par un élément <RewriterRule>. Le modèle à rechercher est défini par l'élément <LookFor>, tandis que la chaîne qui remplace le modèle figure dans l'élément <SentTo>. Ces règles de réécriture sont évaluées de haut en bas. S'il existe une correspondance, l'URL est réécrite et la recherche via les règles de réécriture s'arrête.

Lorsque vous définissez des modèles dans l'élément <LookFor>, notez que des expressions régulières sont utilisées pour établir la correspondance et le remplacement de chaîne. (Dans un moment, nous allons étudier un exemple réel qui explique comment rechercher un modèle en utilisant des expressions régulières.) Du fait que le modèle est une expression régulière, veillez à désactiver les caractères réservés dans les expressions régulières. (Les caractères réservés d'expressions régulières incluent notamment : ., ?, ^, $. Vous pouvez les désactiver en les faisant précéder d'une barre oblique inverse ; par exemple \. équivaut à un point littéral).

Réécriture d'URL avec un module HTTP

Créer un module HTTP est aussi simple que de créer une classe qui implémente l'interface IHttpModule. L'interface IHttpModule définit deux méthodes :

  • Init(HttpApplication). Cette méthode se déclenche lorsque le module HTTP est initialisé. Dans cette méthode, vous liez des gestionnaires d'événements aux événements HttpApplication appropriés.
  • Dispose(). Cette méthode est appelée lorsque la demande est terminée et a été renvoyée à IIS. Un nettoyage final doit être effectué à ce stade.

Pour faciliter la création d'un module HTTP pour la réécriture d'URL, j'ai commencé par créer la classe de base abstraite BaseModuleRewriter. Cette classe implémente IHttpModule. Dans l'événement Init(), elle lie l'événement HttpApplication's AuthorizeRequest à la méthode BaseModuleRewriter_AuthorizeRequest. La méthode BaseModuleRewriter_AuthorizeRequest appelle la méthode Rewrite() de la classe en passant le chemin demandé avec l'objet HttpApplication transmis à la méthode Init(). La méthode Rewrite() est abstraite, ce qui implique que dans la classe BaseModuleRewriter, la méthode Rewrite() ne dispose pas de corps de méthode. En fait, la classe issue de BaseModuleRewriter doit remplacer cette méthode et fournir un corps de méthode.

Avec cette classe de base en place, il nous suffit maintenant de créer une classe issue de BaseModuleRewriter qui remplace Rewrite() et exécute ici le code de réécriture d'URL. Le code de BaseModuleRewriter figure ci-dessous.

public abstract class BaseModuleRewriter : IHttpModule
{
 public virtual void Init(HttpApplication app)
 {
 // WARNING! This does not work with Windows authentication!
 // If you are using Windows authentication, 
 // change to app.BeginRequest
 app.AuthorizeRequest += new 
 EventHandler(this.BaseModuleRewriter_AuthorizeRequest);
 }

 public virtual void Dispose() {}

 protected virtual void BaseModuleRewriter_AuthorizeRequest(
 object sender, EventArgs e)
 {
 HttpApplication app = (HttpApplication) sender;
 Rewrite(app.Request.Path, app);
 }

 protected abstract void Rewrite(string requestedPath, 
 HttpApplication app);
}

Notez que la classe BaseModuleRewriter exécute la réécriture d'URL dans l'événement AuthorizeRequest. Rappelez-vous que si vous utilisez l'authentification Windows avec les autorisations de fichier, vous devez modifier cela pour que la réécriture d'URL soit exécutée dans les événements BeginRequest ou AuthenticateRequest.

La classe ModuleRewriter étend la classe BaseModuleRewriter et elle est chargée d'exécuter la réécriture d'URL. ModuleRewriter contient une seule méthode de remplacement, Rewrite(), qui est indiquée ci-dessous :

protected override void Rewrite(string requestedPath, 
 System.Web.HttpApplication app)
{
 // get the configuration rules
 RewriterRuleCollection rules = 
 RewriterConfiguration.GetConfig().Rules;

 // iterate through each rule...
 for(int i = 0; i < rules.Count; i++)
 {
 // get the pattern to look for, and 
 // Resolve the Url (convert ~ into the appropriate directory)
 string lookFor = "^" + 
 RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, 
 rules[i].LookFor) + "$";

 // Create a regex (note that IgnoreCase is set...)
 Regex re = new Regex(lookFor, RegexOptions.IgnoreCase);

 // See if a match is found
 if (re.IsMatch(requestedPath))
 {
 // match found - do any replacement needed
 string sendToUrl = 
RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, 
 re.Replace(requestedPath, rules[i].SendTo));

 // Rewrite the URL
 RewriterUtils.RewriteUrl(app.Context, sendToUrl);
 break; // exit the for loop
 }
 }
}

La méthode Rewrite() commence par obtenir le jeu de règles de réécriture dans le fichier Web.config. Elle est itérée ensuite sur les règles de réécriture une règle à la fois, et pour chaque règle, elle obtient sa propriété LookFor et elle utilise une expression régulière pour déterminer si une correspondance existe dans l'URL demandée.

Si une correspondance existe, un remplacement d'expression régulière est exécuté dans le chemin demandé avec la valeur de la propriété SendTo. L'URL remplacée est alors envoyée à la méthode RewriterUtils.RewriteUrl(). RewriterUtils est une classe d'assistance qui fournit deux méthodes statiques utilisées par le module HTTP et le gestionnaire HTTP de réécriture d'URL. La méthode RewriterUrl() appelle simplement la méthode RewriteUrl() de l'objet HttpContext.

Remarque    Vous aurez sans doute remarqué que lors de l'établissement de la correspondance et du remplacement à l'aide d'une expression régulière, la méthode RewriterUtils.ResolveUrl() est appelée. Cette méthode d'assistance remplace simplement les instances ~ dans la chaîne par la valeur du chemin de l'application.

Vous pouvez télécharger l'ensemble du code du moteur de réécriture d'URL avec cet article. Nous venons d'examiner les éléments les plus apparentés, mais il existe également d'autres composants, tels que des classes de désérialisation des règles de réécriture de format XML dans le fichier Web.config en un objet, ainsi que des groupes de gestionnaires HTTP de réécriture d'URL. Les trois sections restantes de cet article portent sur des utilisations réelles de réécriture d'URL.

Réécriture d'URL simple avec le moteur de réécriture d'URL

Pour montrer le fonctionnement du moteur de réécriture, nous allons créer une application Web ASP.NET qui utilise la réécriture d'URL simple. Imaginez que vous travaillez pour une société qui vend divers produits en ligne et qu'il existe les catégories de produits suivantes :

ID de catégorie Nom de catégorie
1 Boissons
2 Condiments
3 Confections
4 Produits laitiers
......

Supposons que nous avons déjà créé la page Web ASP.NET ListProductsByCategory.aspx qui accepte une valeur d'ID de catégorie dans la chaîne d'interrogation et affiche tous les produits de la catégorie. Les utilisateurs qui veulent afficher les boissons proposées accèdent à ListProductsByCategory.aspx?CategoryID=1 et ceux qui veulent identifier les produits laitiers accèdent ListProductsByCategory.aspx?CategoryID=4. Supposons également que nous disposons de la page ListCategories.aspx qui affiche la liste des catégories de produits en vente.

À l'évidence, nous pouvons réécrire les URL dans ce cas du fait que les URL présentées à l'utilisateur n'ont aucune signification et ne fournissent pas non plus une « vulnérabilité ». Réécrivons les URL de sorte que, lorsque l'utilisateur visite /Products/Beverages.aspx, l'URL soit réécrite sous la forme ListProductsByCategory.aspx?CategoryID=1. Nous pouvons effectuer cette opération avec la règle de réécriture d'URL suivante dans le fichier Web.config :

<RewriterConfig>
 <Rules>
 <!-- Rules for Product Lister -->
 <RewriterRule>
 <LookFor>~/Products/Beverages\.aspx</LookFor>
 <SendTo>~/ListProductsByCategory.aspx?CategoryID=1</SendTo>
 </RewriterRule>
 <RewriterRule>
 </Rules>
</RewriterConfig>

Comme vous pouvez le constater, cette règle détermine si le chemin demandé par l'utilisateur était /Products/Beverages.aspx. Si tel est le cas, elle réécrit l'URL sous la forme /ListProductsByCategory.aspx?CategoryID=1.

Remarque    Notez que l'élément <LookFor> désactive le point dans Beverages.aspx car la valeur <LookFor> est utilisée dans un modèle d'expression régulière et que le point, dans une expression régulière, correspond à un caractère spécial qui signifie « établir une correspondance avec n'importe quel caractère », ce qui implique que l'URL /Products/BeveragesQaspx, par exemple, pourrait correspondre. En désactivant le point (avec \.), nous indiquons que nous voulons rechercher un point littéral et non un ancien caractère.

Avec cette règle, lorsque l'utilisateur accède à /Products/Beverages.aspx, la liste des boissons s'affiche. La figure 3 est une capture d'écran d'un navigateur qui accède à /Products/Beverages.aspx. Notez que la barre d'adresse du navigateur contient l'URL /Products/Beverages.aspx, mais que l'utilisateur voir en fait le contenu de ListProductsByCategory.aspx?CategoryID=1 (en fait, il n'existe aucun fichier /Products/Beverages.aspx sur le serveur Web !).

urlrewriting_fig03.gif

Figure 3. Demande de catégorie après réécriture d'URL

Comme pour /Products/Beverages.aspx, nous devons maintenant ajouter des règles de réécriture pour les autres catégories de produits. Il suffit d'ajouter d'autres éléments <RewriterRule> dans l'élément <Rules> du fichier Web.config. Consultez le fichier Web.config que vous avez téléchargé pour identifier le jeu de règles complet de règles de réécriture de la démonstration.

Pour rendre l'URL encore plus « abrégeable », il serait intéressant de pouvoir permettre à un utilisateur de simplement abréger /Products/Beverages.aspx en Beverages.aspx et d'afficher la catégorie des produits. À première vue, la tâche semble simple ; il suffit d'ajouter une règle de réécriture qui associe /Products/ à /ListCategories.aspx. Toutefois, il existe une petite subtilité ; vous devez créer préalablement le répertoire /Products/ et y ajouter un fichier Default.aspx vide.

Pour comprendre pourquoi il est nécessaire de procéder ainsi, souvenez-vous que le moteur de réécriture d'URL se trouve au niveau ASP.NET. En fait, si le moteur ASP.NET n'a jamais la possibilité de traiter la demande, le moteur de réécriture d'URL ne peut pas analyser l'URL entrante. Souvenez-vous aussi que IIS transmet les demandes entrantes au moteur ASP.NET uniquement si le fichier demandé porte une extension appropriée. Ainsi, si l'utilisateur accède à /Products/, IIS ne détecte aucune extension de fichier et il vérifie si le répertoire contient un fichier portant l'un des noms de fichiers par défaut. (Default.aspx, Default.htm, Default.asp, etc. Ces noms de fichiers par défaut sont définis dans l'onglet Documents de la boîte de dialogue des propriétés Web Server dans la boîte de dialogue de l'outil d'administration IIS.) Naturellement, si le répertoire /Products/ n'existe pas, IIS retourne une erreur HTTP 404.

Il est donc nécessaire de créer le répertoire /Products/. D'autre part, nous devons créer un seul fichier, Default.aspx, dans ce répertoire. Ainsi, lorsque l'utilisateur accède à /Products/, IIS analyse le répertoire, détermine que le fichier Default.aspx existe et transmet le traitement au moteur ASP.NET. Le programme de réécriture d'URL réécrira alors rapidement l'URL.

Après avoir créé le répertoire et le fichier Default.aspx, ajoutez la règle de réécriture suivante à l'élément <Rules> :

<RewriterRule>
 <LookFor>~/Products/Default\.aspx</LookFor>
 <SendTo>~/ListCategories.aspx</SendTo>
</RewriterRule>

Une fois la règle ajoutée, l'utilisateur affiche la liste des catégories de produits (figure 4) lorsqu'il accède à /Products/ ou à /Products/Default.aspx.

urlrewriting_fig04.gif

Figure 4. Ajout d'« abrégeabilité » à l'URL

Gestion des publications

Si les URL que vous réécrivez contiennent un formulaire Web côté serveur et effectuent des publications, l'URL sous-jacente est utilisée lors de la publication du formulaire. En effet, si l'utilisateur tape dans son navigateur /Products/Beverages.aspx, la barre d'adresse du navigateur contient /Products/Beverages.aspx, mais il affiche le contenu de ListProductsByCategory.aspx?CategoryID=1. Si ListProductsByCategory.aspx effectue une publication, l'utilisateur est renvoyé vers ListProductsByCategory.aspx?CategoryID=1 et non vers /Products/Beverages.aspx, ce qui n'a aucune conséquence proprement dite, sauf que l'utilisateur risque d'être surpris de voir l'URL changer soudainement en cliquant sur un bouton.

Cette situation se produit car, lors du rendu du formulaire, ce dernier affecte à son attribut d'action la valeur du chemin du fichier dans l'objet Request. Naturellement, lorsque le formulaire Web aura été rendu, l'URL /Products/Beverages.aspx aura déjà été convertie en ListProductsByCategory.aspx?CategoryID=1, ce qui signifie que l'objet Request signale que l'utilisateur visite ListProductsByCategory.aspx?CategoryID=1. Vous pouvez résoudre ce problème en empêchant le formulaire côté serveur de rendre un attribut d'action. (Par défaut, les navigateurs effectuent une publication si le formulaire ne contient pas d'attribut d'action.)

Malheureusement, le formulaire Web ne permet pas de spécifier explicitement un attribut d'action ni de définir une propriété pour désactiver le rendu de l'attribut d'action. Vous devez donc étendre vous-même la classe System.Web.HtmlControls.HtmlForm en remplaçant la méthode RenderAttribute() et en indiquant explicitement qu'elle ne rende par l'attribut d'action.

Grâce à la puissance de l'héritage, nous pouvons bénéficier de toute la fonctionnalité de la classe HtmlForm et n'avons qu'à ajouter quelques lignes de code pour obtenir le comportement souhaité. Le code complet de la classe personnalisée figure ci-après :

namespace ActionlessForm {
 public class Form : System.Web.UI.HtmlControls.HtmlForm
 {
 protected override void RenderAttributes(HtmlTextWriter writer)
 {
 writer.WriteAttribute("name", this.Name);
 base.Attributes.Remove("name");

 writer.WriteAttribute("method", this.Method);
 base.Attributes.Remove("method");

 this.Attributes.Render(writer);

 base.Attributes.Remove("action");

 if (base.ID != null)
 writer.WriteAttribute("id", base.ClientID);
 }
 }
}

Le code de remplacement de la méthode RenderAttributes() contient simplement le code exact de la méthode RenderAttributes() de la classe HtmlForm, mais sans l'attribut d'action (j'ai utilisé Reflector Lien externe au site MSDN France Site en anglais de Lutz Roeder pour afficher le code source de la classe HtmlForm).

Une fois cette classe créée et compilée, ajoutez-la au dossier References de l'application Web pour pouvoir l'utiliser dans l'application Web ASP.NET. Utilisez-la ensuite à la place de la classe HtmlForm en ajoutant les informations suivantes en haut de la page Web ASP.NET :

<%@ Register TagPrefix="skm" Namespace="ActionlessForm" 
 Assembly="ActionlessForm" %>

Remplacez ensuite <form runat="server"> par

<skm:Form id="Form1" method="post" runat="server">

et remplacez la balise de fermeture </form> par

</skm:Form>

Vous pouvez voir l'action de cette classe Web Form personnalisée dans ListProductsByCategory.aspx que vous avez téléchargé avec cet article. Le module téléchargeable inclut également un projet Visual Studio .NET pour le formulaire Web sans action.

Remarque    Si l'URL réécrite n'effectue pas de publication, il est inutile d'utiliser cette classe Web Form personnalisée.

Création d'URL véritablement « abrégeable »

La réécriture d'URL simple décrite dans la section précédente montre la simplicité de configuration du moteur de réécriture d'URL avec de nouvelles règles de réécriture. La vraie puissance des règles de réécriture se révèle néanmoins en utilisant des expressions régulières, comme nous allons le voir dans la section suivante.

Les blogs connaissent un grand engouement et il semble que tout le monde ait le sien. Si les blogs ne vous sont pas familiers, il s'agit de pages personnelles régulièrement mises à jour qui font office de journal personnel en ligne. La plupart des utilisateurs de blog commentent simplement leur journée, alors que d'autres abordent des thèmes spécifiques tels que le cinéma, une équipe sportive ou l'informatique.

Selon l'auteur, le blog peut être mis à jour plusieurs fois par jour ou une fois par semaine ou toutes les deux semaines. En règle générale, la page d'accueil du blog contient les dix dernières entrées, mais la plupart des programmes de création de blogs fournissent une archive qui permet aux visiteurs d'afficher les publications antérieures. Les blogs Web se prêtent par excellence à la réécriture d'URL. Supposons que lors de la consultation des archives d'un blog, vous accédiez à l'URL /2004/02/14.aspx. Seriez-vous vraiment surpris de lire les publications publiées le 14 février 2004 ? Vous pourriez aussi vouloir afficher toutes les publications de février 2004 dans quel cas voudriez tenter d'abréger l'URL à /2004/02/. Pour afficher toutes les publications de 2004, vous pourriez tenter d'accéder à /2004/.

Lors de la gestion d'un blog, il serait utile de fournir aux visiteurs ce niveau d'« abrégeabilité » d'URL. Bien que la plupart des moteurs de blog fournissent cette fonctionnalité, analysons comment nous pouvons procéder en utilisant la réécriture d'URL.

Tout d'abord, nous devons utiliser une page ASP.NET qui affiche les entrées du blog pour chaque jour, mois ou année. Supposons que nous disposons de la page ShowBlogContent.aspx qui utilise les paramètres de chaîne d'interrogation Année, Mois et Jour. Pour afficher les publications du 14 février 2004, nous pouvons accéder à ShowBlogContent.aspx?year=2004&month=2&day=14, pour afficher toutes les publications de février 2004, nous visitions ShowBlogContent.aspx?year=2004&month=2 et pour afficher toutes les publications de l'année 2004, nous accédons à ShowBlogContent.aspx?year=2004 (le code de ShowBlogContent.aspx figure dans le module téléchargeable de cet article).

Donc, si l'utilisateur accède à /2004/02/14.aspx, nous devons réécrire l'URL en ShowBlogContent.aspx?year=2004&month=2&day=14. Les trois cas, lorsque l'URL définit une année, un mois et un jour, lorsque l'URL définit uniquement l'année et le mois et lorsque l'URL définit uniquement l'année, peuvent être gérés avec trois règles de réécriture :

<RewriterConfig>
 <Rules>
 <!-- Rules for Blog Content Displayer -->
 <RewriterRule>
 <LookFor>~/(\d{4})/(\d{2})/(\d{2})\.aspx</LookFor>
 <SendTo>~/ShowBlogContent.aspx?year=$1&amp;month=$2&amp;day=$3</SendTo>
 </RewriterRule>
 <RewriterRule>
 <LookFor>~/(\d{4})/(\d{2})/Default\.aspx</LookFor>
 <SendTo><![CDATA[~/ShowBlogContent.aspx?year=$1&month=$2]]></SendTo>
 </RewriterRule>
 <RewriterRule>
 <LookFor>~/(\d{4})/Default\.aspx</LookFor>
 <SendTo>~/ShowBlogContent.aspx?year=$1</SendTo>
 </RewriterRule>
 </Rules>
</RewriterConfig>

Ces règles montrent la puissance des expressions régulières. Dans la première règle, nous recherchons une URL avec le modèle (\d{4})/(\d{2})/(\d{2})\.aspx. En bon français, cela correspond à une chaîne constituée de quatre chiffres suivie d'une barre oblique suivie de deux chiffres suivis d'une barre oblique suivie de deux chiffres suivis de .aspx. Les parenthèses autour des groupes de chiffres sont essentielles ; elles permettent de faire référence aux caractères de correspondance dans ces parenthèses dans la propriété <SendTo> correspondante. De manière plus spécifique, nous pouvons faire référence aux groupes à parenthèses de correspondance en utilisant $1, $2 et $3 pour le premier, le deuxième et le troisième groupe à parenthèses.

Remarque    Du fait que le fichier Wb.config est de format XML, les caractères tels que &, < et > dans la partie texte d'un élément doivent être désactivés. Dans l'élément <SendTo> de la première règle, & est désactivé par &. Dans l'élément <SendTo> de la deuxième règle, une technique alternative est utilisée : en utilisant un élément <![CDATA[...]]>, il n'est pas nécessaire de désactiver le contenu à l'intérieur. Les deux approches sont acceptables et donnent le même résultat.

Les figures 5, 6 et 7 montrent l'opération de réécriture d'URL. Les données sont en fait extraites de mon blog http://scottonwriting.net/ Lien externe au site MSDN France Site en anglais. La figure 5 contient les publications du 7 novembre 2003, la figure 6 contient toutes les publications de novembre 2003 et la figure 7, celles de toutes les publications de 2003.

urlrewriting_fig05.gi

Figure 5. Publications du 7 novembre 2003

urlrewriting_fig06.gif

Figure 6. Toutes les publications de novembre 2003

urlrewriting_fig07.gif

Figure 7. Toutes les publications de 2003

Remarque    Le moteur de réécriture d'URL attend un modèle d'expression régulière dans les éléments <LookFor>. Si vous maîtrisez les expressions régulières, lisez l'un de mes articles précédents An Introduction to Regular Expressions Lien externe au site MSDN France Site en anglais. En outre, le site http://regexlib.com/RegExLib.com Lien externe au site MSDN France Site en anglais contient les expressions régulières les plus utilisées et constitue un référentiel pour partager vos propres expressions régulières.

Création de la structure de répertoires nécessaire

Lorsque /2004/03/19.aspx est demandé, IIS note l'extension .aspx et envoie la demande au moteur ASP.NET. Tandis que la demande transite dans le moteur ASP.NET, l'URL est réécrite en ShowBlogContent.aspx?year=2004&month=03&day=19 et le visiteur affiche les entrées du 19 mars 2004 du blog. Mais que se passe-t-il lorsqu'il accède à /2004/03/ ? S'il n'existe pas de répertoire /2004/03/, IIS retourne l'erreur 404. En outre, ce répertoire doit contenir une page Default.aspx pour que la demande soit remise au moteur ASP.NET.

Dans le cadre de cette approche, vous devez donc créer manuellement un répertoire pour chaque année associée à des publications et le répertoire doit contenir une page Default.aspx. D'autre part, pour chaque répertoire d'année, vous devez créer manuellement douze répertoires (01, 02, …, 12) contenant chacun un fichier Default.aspx. (Souvenez-vous que nous avons dû procéder ainsi, ajouter le répertoire /Products/ avec un fichier Default.aspx, dans la démonstration précédente pour afficher correctement ListCategories.aspx lors de la visite de /Products/.)

À l'évidence, l'ajout d'une structure de répertoire est rébarbatif. Pour éviter d'avoir à le faire, il suffit d'associer les demandes IIS entrantes au moteur ASP.NET. Ainsi, lors de l'accès à l'URL /2004/03/, IIS enverra toujours la demande au moteur ASP.NET, même s'il n'existe pas un répertoire /2004/03/. Dans le cadre de cette approche, toutefois, le moteur ASP.NET est chargé de traiter tous les types de demandes entrantes vers le serveur Web, y compris les images, les fichiers CSS, les fichiers externes JavaScript, les fichiers Macromedia Flash, etc.

L'analyse détaillée du traitement de tous les types de fichiers n'entre pas du tout dans le cadre de cet article. Pour un exemple d'application Web ASP.NET qui utilise cette technique, reportez-vous au moteur de blog Open Source .Text. .Text peut être configuré pour associer toutes les demandes au moteur ASP.NET. Il peut prendre en charge la gestion de tous les types de fichiers en utilisant un gestionnaire HTTP personnalisé qui sait gérer les types de fichiers statiques types (images, fichiers CSS, etc.).

Conclusion

Dans cet article, nous avons vu comment réécrire des URL au niveau ASP.NET en utilisant la méthode RewriteUrl() de la classe HttpContext. Comme nous l'avons vu, RewriteUrl() met à jour la propriété Request de la classe HttpContext's, qui met à jour le fichier et le chemin demandés. Du point de vue de l'utilisateur, le visiteur accède à une URL, mais, en fait, une URL différente est demandée au serveur Web.

Les URL peuvent être réécrites dans un module HTTP ou dans un gestionnaire HTTP. Dans cet article, nous avons examiné l'utilisation d'un module HTTP pour la réécriture et analysé les conséquences de la réécriture à différentes étapes.

Naturellement, en procédant au niveau ASP.NET, la réécriture d'URL ne peut avoir lieu que si la demande est transmise d'IIS au moteur ASP.NET. Cela se produit naturellement lorsque l'utilisateur demande une page ayant l'extension .aspx. Toutefois, si vous voulez permettre à l'utilisateur de taper une URL qui n'existe pas réellement, mais qui est réécrite pour afficher une page ASP.NET existante, vous devez créer des « faux » répertoires et pages Default.aspx ou configurer IIS pour envoyer systématiquement toutes les demandes entrantes au moteur ASP.NET.

Bibliographie

ASP.NET: Tips, Tutorials, and Code Lien externe au site MSDN France Site en anglais

Microsoft ASP.NET Coding Strategies with the Microsoft ASP.NET Team Lien externe au site MSDN France Site en anglais

Essential ASP.NET with Examples in C# Lien externe au site MSDN France Site en anglais

Manuels consultés

La réécriture d'URL est un sujet d'attention tant pour ASP.NET que pour les fournisseurs de technologies Web serveur concurrents du marché. Le serveur Web Apache, par exemple, fournit le module de réécriture d'URL mod_rewrite Lien externe au site MSDN France Site en anglais. mod_rewrite est un moteur de réécriture efficace qui fournit des règles de réécriture en fonction de conditions, telles que des en-têtes HTTP et des variables de serveur, ainsi que des règles de réécriture qui utilisent des expressions régulières. Pour plus d'informations sur mod_rewrite, reportez-vous à A User's Guide to URL Rewriting with the Apache Web Server Lien externe au site MSDN France Site en anglais.

Il existe un certain nombre d'articles sur la réécriture d'URL avec ASP.NET. Rewrite.NET - A URL Rewriting Engine for .NET Lien externe au site MSDN France Site en anglais porte sur un moteur de réécriture d'URL qui émule les règles d'expressions régulières de mod_rewrite. URL Rewriting With ASP.NET donne également un bon aperçu des fonctions de réécriture d'URL d' ASP.NET. Ian Griffiths Lien externe au site MSDN France Site en anglais dispose d'un http://www.interact-sw.co.uk/iangblog/2004/01/12/shinyurl blog Lien externe au site MSDN France Site en anglais sur les problèmes associés à la réécriture d'URL avec ASP.NET, notamment sur la publication abordée dans cet article. Fabrice Marguerie Lien externe au site MSDN France Site en anglais (http://weblogs.asp.net/fmarguerie/archive/2003/12/24/45712.aspx en savoir plus Lien externe au site MSDN France Site en anglais) et http://weblogs.asp.net/jasonsalas/Jason Salas Lien externe au site MSDN France Site en anglais (http://weblogs.asp.net/jasonsalas/archive/2003/12/14/43404.aspx en savoir plus Lien externe au site MSDN France Site en anglais) disposent d'un blog sur la réécriture d'URL pour améliorer l'emplacement des moteurs de recherche.

 

À propos de l'auteur

Scott Mitchell, auteur de cinq manuels et fondateur de 4GuysFromRolla.com, travaille sur les technologies Web de Microsoft depuis cinq ans. Scott travaille comme consultant, formateur et auteur indépendant. Vous pouvez le contacter à l'adresse mitchell@4guysfromrolla.com ou via son blog accessible à l'adresse http://scottonwriting.net/ Lien externe au site MSDN France Site en anglais.



Dernière mise à jour le vendredi 11 juin 2004



Afficher: