URL-Umschreiben in ASP.NET

 

Scott Mitchell
4GuysFromRolla.com

März 2004

Gilt für:
   Microsoft® ASP.NET

Zusammenfassung: Untersucht, wie Sie dynamisches URL-Umschreiben mit Microsoft ASP.NET durchführen. Url-Umschreiben ist der Prozess des Abfangens einer eingehenden Webanforderung und der automatischen Umleitung an eine andere URL. Erläutert die verschiedenen Techniken zum Implementieren des URL-Umschreibens und untersucht reale Szenarien des URL-Umschreibens. (31 gedruckte Seiten)

Laden Sie den Quellcode für diesen Artikel herunter.

Inhalte

Einführung
Allgemeine Verwendung von URL-Umschreiben
Was geschieht, wenn eine Anforderung IIS erreicht?
Implementieren des URL-Umschreibens
Erstellen einer URL-Umschreibungs-Engine
Ausführen eines einfachen URL-Umschreibens mit der URL-Umschreibungs-Engine
Erstellen wirklich "hackbarer" URLs
Zusammenfassung
Verwandte Bücher

Einführung

Nehmen Sie sich einen Moment Zeit, um einige der URLs auf Ihrer Website zu betrachten. Finden Sie URLs wie http://yoursite.com/info/dispEmployeeInfo.aspx?EmpID=459-099\&type=summary? Oder vielleicht haben Sie eine Reihe von Webseiten, die von einem Verzeichnis oder einer Website in ein anderes verschoben wurden, was zu fehlerhaften Links für Besucher führt, die die alten URLs mit Lesezeichen versehen haben. In diesem Artikel untersuchen wir die Verwendung des URL-Umschreibens, um diese hässlichen URLs auf aussagekräftige, einprägsame URLs zu verkürzen, indem type=summary durch etwas wie ersetzthttp://yoursite.com/info/dispEmployeeInfo.aspx?EmpID=459-099\& wird.http://yoursite.com/people/sales/chuck.smith Außerdem wird erläutert, wie das Umschreiben von URL verwendet werden kann, um einen intelligenten 404-Fehler zu erstellen.

Beim URL-Umschreiben wird eine eingehende Webanforderung abgefangen und die Anforderung an eine andere Ressource umgeleitet. Beim Durchführen des URL-Umschreibens wird in der Regel die angeforderte URL überprüft, und basierend auf ihrem Wert wird die Anforderung an eine andere URL umgeleitet. Wenn beispielsweise eine Websiteumstrukturierung dazu führte, dass alle Webseiten im Verzeichnis /people/ in ein Verzeichnis /info/employees/ verschoben wurden, sollten Sie das URL-Umschreiben verwenden, um zu überprüfen, ob eine Webanforderung für eine Datei im Verzeichnis /people/ vorgesehen war. Wenn es sich bei der Anforderung um eine Datei im Verzeichnis /people/ handelt, sollten Sie die Anforderung automatisch an dieselbe Datei umleiten, sondern stattdessen im Verzeichnis /info/employees/.

Bei klassischem ASP bestand die einzige Möglichkeit, das URL-Umschreiben zu nutzen, darin, einen ISAPI-Filter zu schreiben oder ein Drittanbieterprodukt zu kaufen, das Url-Umschreibungsfunktionen bot. Mit Microsoft® ASP.NET können Sie jedoch ganz einfach Ihre eigene URL-Umschreibungssoftware auf verschiedene Arten erstellen. In diesem Artikel untersuchen wir die Techniken, die ASP.NET Entwicklern für die Implementierung des URL-Umschreibens zur Verfügung stehen, und wenden uns dann einigen realen Verwendungen des URL-Umschreibens zu. Bevor wir uns mit den technologischen Besonderheiten des URL-Umschreibens befassen, werfen wir zunächst einen Blick auf einige alltägliche Szenarien, in denen das URL-Umschreiben verwendet werden kann.

Allgemeine Verwendung von URL-Umschreiben

Das Erstellen von datengesteuerten ASP.NET Websites führt häufig zu einer einzelnen Webseite, die eine Teilmenge der Datenbankdaten basierend auf Abfragezeichenfolgenparametern anzeigt. Beim Entwerfen einer E-Commerce-Website besteht beispielsweise eine Ihrer Aufgaben darin, Benutzern das Durchsuchen der zum Verkauf angebotenen Produkte zu ermöglichen. Um dies zu erleichtern, können Sie eine Seite namens displayCategory.aspx erstellen, auf der die Produkte für eine bestimmte Kategorie angezeigt werden. Die anzuzeigenden Produkte der Kategorie werden durch einen Querystring-Parameter angegeben. Das heißt, wenn der Benutzer die Widgets zum Verkauf durchsuchen möchte und alle Widgets eine CategoryID von 5 hatten, würde der Benutzer Folgendes besuchen: http://yousite.com/displayCategory.aspx?CategoryID=5.

Es gibt zwei Nachteile beim Erstellen einer Website mit solchen URLs. Erstens ist die URL http://yousite.com/displayCategory.aspx?CategoryID=5 aus Sicht des Endbenutzers ein Chaos. Benutzerfreundlichkeitsexperte Jakob Neilsenempfiehlt, URLs so zu wählen, dass sie:

  • Sind kurz.
  • Sind einfach zu eingeben.
  • Visualisieren Sie die Websitestruktur.
  • "Hackbar", sodass der Benutzer durch die Website navigieren kann, indem er Teile der URL abhackt.

Ich würde dieser Liste hinzufügen, dass URLs auch leicht zu merken sein sollten. Die URL http://yousite.com/displayCategory.aspx?CategoryID=5 erfüllt keines der Kriterien von Neilsen und ist auch nicht leicht zu merken. Wenn Benutzer aufgefordert werden, Abfragezeichenfolgenwerte einzugeben, kann eine URL schwer eingegeben werden, und die URL kann nur von erfahrenen Webentwicklern "hackbar" werden, die den Zweck von Abfragezeichenfolgenparametern und deren Name-Wert-Paarstruktur verstehen.

Ein besserer Ansatz besteht darin, eine sinnvolle, einprägsame URL wie zuzulassen http://yoursite.com/products/Widgets. Wenn Sie sich nur die URL ansehen, können Sie ableiten, was angezeigt wird – Informationen zu Widgets. Die URL ist leicht zu merken und zu teilen. Ich kann meinem Kollegen sagen: "Check out yoursite.com/products/Widgets", und sie wird wahrscheinlich die Seite aufrufen können, ohne mich erneut fragen zu müssen, was die URL war. (Versuchen Sie, dies mit einer Amazon.com Seite zu tun!) Die URL wird auch angezeigt und sollte sich als "hackbar" verhalten. Das heißt, wenn der Benutzer das Ende der URL hackt und in http://yoursite.com/productseingibt, sollte eine Liste aller Produkte oder zumindest eine Liste aller Kategorien von Produkten angezeigt werden, die er anzeigen kann.

Hinweis Als Beispiel für eine "hackbare" URL sehen Sie sich die URLs an, die von vielen Blog-Engines generiert werden. Um die Beiträge für den 28. Januar 2004 anzuzeigen, besucht man eine URL wie http://someblog.com/2004/01/28. Wenn die URL auf http://someblog.com/2004/01gehackt wird, werden dem Benutzer alle Beiträge für Januar 2004 angezeigt. Wenn Sie sie weiter herunterschneiden, http://someblog.com/2004 werden alle Beiträge für das Jahr 2004 angezeigt.

Neben der Vereinfachung von URLs wird das URL-Umschreiben auch häufig verwendet, um die Umstrukturierung von Websites zu bewältigen, die andernfalls zu zahlreichen fehlerhaften Links und veralteten Lesezeichen führen würde.

Was geschieht, wenn eine Anforderung IIS erreicht?

Bevor wir uns genau mit der Implementierung von URL-Umschreibungen befassen, ist es wichtig, dass wir wissen, wie eingehende Anforderungen von Microsoft® Internet Information Services (IIS) verarbeitet werden. Wenn eine Anforderung bei einem IIS-Webserver eintrifft, untersucht IIS die Erweiterung der angeforderten Datei, um zu bestimmen, wie die Anforderung behandelt wird. Anforderungen können von IIS nativ behandelt werden – ebenso wie HTML-Seiten, Bilder und andere statische Inhalte – oder IIS kann die Anforderung an eine ISAPI-Erweiterung weiterleiten. (Eine ISAPI-Erweiterung ist eine nicht verwaltete, kompilierte Klasse, die eine eingehende Webanforderung verarbeitet. Seine Aufgabe besteht darin, den Inhalt für die angeforderte Ressource zu generieren.)

Wenn beispielsweise eine Anforderung für eine Webseite mit dem Namen Info.asp eingeht, leitet IIS die Nachricht an die asp.dll ISAPI-Erweiterung weiter. Diese ISAPI-Erweiterung lädt dann die angeforderte ASP-Seite, führt sie aus und gibt den gerenderten HTML-Code an IIS zurück, der sie dann an den anfordernden Client zurück sendet. Für ASP.NET Seiten leitet IIS die Nachricht an die aspnet_isapi.dll ISAPI-Erweiterung weiter. Die aspnet_isapi.dll ISAPI-Erweiterung übergibt dann die Verarbeitung an den verwalteten ASP.NET Workerprozess, der die Anforderung verarbeitet und den gerenderten HTML-Code der ASP.NET Webseite zurückgibt.

Sie können IIS anpassen, um anzugeben, welche Erweiterungen welchen ISAPI-Erweiterungen zugeordnet sind. Abbildung 1 zeigt das Dialogfeld Anwendungskonfiguration aus dem Verwaltungstool für Internetinformationsdienste. Beachten Sie, dass die ASP.NET-bezogenen Erweiterungen –.aspx, .ascx, .config, .asmx, .rem, .cs, .vb und andere – der aspnet_isapi.dll ISAPI-Erweiterung zugeordnet sind.

ms972974.urlrewriting_fig01(en-us,MSDN.10).gif

Abbildung 1. Konfigurierte Zuordnungen für Dateierweiterungen

Eine ausführliche Diskussion darüber, wie IIS eingehende Anforderungen verwaltet, liegt etwas außerhalb des Rahmens dieses Artikels. Eine großartige, ausführliche Diskussion finden Sie jedoch in Michele Leroux Bustamantes Artikel Inside IIS and ASP.NET. Es ist wichtig zu verstehen, dass die ASP.NET-Engine nur eingehende Webanforderungen erhält, deren Erweiterungen explizit dem aspnet_isapi.dll in IIS zugeordnet sind.

Untersuchen von Anforderungen mit ISAPI-Filtern

Zusätzlich zum Zuordnen der Dateierweiterung der eingehenden Webanforderung zur entsprechenden ISAPI-Erweiterung führt IIS auch eine Reihe anderer Aufgaben aus. Iis versucht beispielsweise, den Benutzer zu authentifizieren, der die Anforderung stellt, und ermittelt, ob der authentifizierte Benutzer über eine Autorisierung für den Zugriff auf die angeforderte Datei verfügt. Während der Lebensdauer der Verarbeitung einer Anforderung durchläuft IIS mehrere Zustände. In jedem Zustand löst IIS ein Ereignis aus, das programmgesteuert mithilfe von ISAPI-Filtern behandelt werden kann.

Wie ISAPI-Erweiterungen sind ISAPI-Filter Blöcke nicht verwalteten Codes, der auf dem Webserver installiert ist. ISAPI-Erweiterungen sind so konzipiert, dass die Antwort für eine Anforderung an einen bestimmten Dateityp generiert wird. ISAPI-Filter enthalten dagegen Code, um auf Ereignisse zu reagieren, die von IIS ausgelöst werden. ISAPI-Filter können die ein- und ausgehenden Daten abfangen und sogar ändern. ISAPI-Filter verfügen über zahlreiche Anwendungen, darunter:

  • Authentifizierung und Autorisierung:
  • Protokollierung und Überwachung.
  • HTTP-Komprimierung.
  • URL-Umschreiben.

Während ISAPI-Filter zum Durchführen des URL-Umschreibens verwendet werden können, wird in diesem Artikel die Implementierung des URL-Umschreibens mithilfe von ASP.NET untersucht. Wir werden jedoch die Kompromisse zwischen der Implementierung des URL-Umschreibens als ISAPI-Filter und der Verwendung der in ASP.NET verfügbaren Techniken erörtern.

Was geschieht, wenn eine Anforderung in die ASP.NET-Engine eintritt?

Vor ASP.NET musste das URL-Umschreiben auf IIS-Webservern mithilfe eines ISAPI-Filters implementiert werden. Das Umschreiben von URLs ist mit ASP.NET möglich, da die ASP.NET-Engine dem IIS auffallend ähnelt. Die Ähnlichkeiten ergeben sich, weil die ASP.NET-Engine:

  1. Löst Ereignisse aus, während eine Anforderung verarbeitet wird.
  2. Ermöglicht eine beliebige Anzahl von HTTP-Modulen die Behandlung der ausgelösten Ereignisse, ähnlich den ISAPI-Filtern von IIS.
  3. Delegatten, die die angeforderte Ressource an einen HTTP-Handler rendern, der den ISAPI-Erweiterungen von IIS ähnelt.

Wie IIS löst das ASP.NET-Modul während der Lebensdauer einer Anforderung Ereignisse aus, die seine Änderung von einem Verarbeitungszustand zu einem anderen signalisieren. Das BeginRequest-Ereignis wird beispielsweise ausgelöst, wenn die ASP.NET-Engine zum ersten Mal auf eine Anforderung antwortet. Als Nächstes wird das AuthenticateRequest-Ereignis ausgelöst, das auftritt, wenn die Identität des Benutzers eingerichtet wurde. (Es gibt zahlreiche andere Ereignisse, darunter AuthorizeRequest, ResolveRequestCache und EndRequest. Diese Ereignisse sind Ereignisse der System.Web.HttpApplication-Klasse . Weitere Informationen finden Sie in der technischen Dokumentation httpApplication Class Overview .)

Wie im vorherigen Abschnitt erläutert, können ISAPI-Filter erstellt werden, um auf die von IIS ausgelösten Ereignisse zu reagieren. In ähnlicher Weise stellt ASP.NET HTTP-Module bereit, die auf die von der ASP.NET-Engine ausgelösten Ereignisse reagieren können. Eine ASP.NET Webanwendung kann mit mehreren HTTP-Modulen konfiguriert werden. Für jede Anforderung, die von der ASP.NET-Engine verarbeitet wird, wird jedes konfigurierte HTTP-Modul initialisiert und kann Ereignishandler mit den Ereignissen verknüpfen, die während der Verarbeitung der Anforderung ausgelöst werden. Beachten Sie, dass für jede Anforderung eine Reihe von integrierten HTTP-Modulen verwendet wird. Eines der integrierten HTTP-Module ist formsAuthenticationModule, das zuerst überprüft, ob die Formularauthentifizierung verwendet wird und, falls ja, ob der Benutzer authentifiziert ist. Andernfalls wird der Benutzer automatisch zur angegebenen Anmeldeseite umgeleitet.

Denken Sie daran, dass bei IIS eine eingehende Anforderung schließlich an eine ISAPI-Erweiterung weitergeleitet wird, deren Aufgabe es ist, die Daten für die jeweilige Anforderung zurückzugeben. Wenn beispielsweise eine Anforderung für eine klassische ASP-Webseite eingeht, übergibt IIS die Anforderung an die asp.dll ISAPI-Erweiterung, deren Aufgabe es ist, das HTML-Markup für die angeforderte ASP-Seite zurückzugeben. Die ASP.NET-Engine verwendet einen ähnlichen Ansatz. Nach der Initialisierung der HTTP-Module besteht die nächste Aufgabe der ASP.NET-Engine darin, zu bestimmen, welcher HTTP-Handler die Anforderung verarbeiten soll.

Alle Anforderungen, die die ASP.NET-Engine durchlaufen, gelangen schließlich an einen HTTP-Handler oder eine HTTP-Handlerfactory (eine HTTP-Handlerfactory gibt einfach eine instance eines HTTP-Handlers zurück, der dann zum Verarbeiten der Anforderung verwendet wird). Der endgültige HTTP-Handler rendert die angeforderte Ressource und gibt die Antwort zurück. Diese Antwort wird an IIS zurückgesendet, die sie dann an den Benutzer zurückgibt, der die Anforderung gestellt hat.

ASP.NET enthält eine Reihe integrierter HTTP-Handler. Die PageHandlerFactory wird beispielsweise verwendet, um ASP.NET Webseiten zu rendern. Die WebServiceHandlerFactory wird verwendet, um die Soap-Umschläge der Antwort für ASP.NET Webdienste zu rendern. Der TraceHandler rendert das HTML-Markup für Anforderungen an trace.axd.

Abbildung 2 zeigt, wie eine Anforderung für eine ASP.NET-Ressource behandelt wird. Zunächst empfängt IIS die Anforderung und sendet sie an aspnet_isapi.dll. Als Nächstes initialisiert die ASP.NET-Engine die konfigurierten HTTP-Module. Schließlich wird der richtige HTTP-Handler aufgerufen, und die angeforderte Ressource wird gerendert, wodurch das generierte Markup an IIS und zurück an den anfordernden Client zurückgegeben wird.

ms972974.urlrewriting_fig02(en-us,MSDN.10).gif

Abbildung 2. Anforderungsverarbeitung durch IIS und ASP.NET

Erstellen und Registrieren benutzerdefinierter HTTP-Module und HTTP-Handler

Das Erstellen benutzerdefinierter HTTP-Module und HTTP-Handler sind relativ einfache Aufgaben, bei denen eine verwaltete Klasse erstellt wird, die die richtige Schnittstelle implementiert. HTTP-Module müssen die System.Web.IHttpModule-Schnittstelle implementieren, während HTTP-Handler und HTTP-Handlerfactorys die System.Web.IHttpHandler-Schnittstelle bzw. die System.Web.IHttpHandlerFactory-Schnittstelle implementieren müssen. Die Besonderheiten der Erstellung von HTTP-Handlern und HTTP-Modulen sprengen den Rahmen dieses Artikels. Einen guten Hintergrund finden Sie im Artikel von Mansoor Ahmed Siddiqui http Handlers and HTTP Modules in ASP.NET.

Nachdem ein benutzerdefiniertes HTTP-Modul oder HTTP-Handler erstellt wurde, muss es bei der Webanwendung registriert werden. Das Registrieren von HTTP-Modulen und HTTP-Handlern für einen gesamten Webserver erfordert nur eine einfache Ergänzung der machine.config-Datei. Das Registrieren eines HTTP-Moduls oder HTTP-Handlers für eine bestimmte Webanwendung umfasst das Hinzufügen einiger XML-Zeilen zur Web.config-Datei der Anwendung.

Fügen Sie insbesondere zum Hinzufügen eines HTTP-Moduls zu einer Webanwendung die folgenden Zeilen im Abschnitt configuration/system.web des Web.config hinzu:

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

Der Typwert stellt die Assembly und den Klassennamen des HTTP-Moduls bereit, während der Namewert einen Anzeigenamen bereitstellt, mit dem in der Datei Global.asax auf das HTTP-Modul verwiesen werden kann.

HTTP-Handler und HTTP-Handlerfactorys werden wie folgt vom <httpHandlers-Tag> im Abschnitt configuration/system.web des Web.config konfiguriert:

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

Beachten Sie, dass die ASP.NET-Engine für jede eingehende Anforderung bestimmt, welcher HTTP-Handler zum Rendern der Anforderung verwendet werden soll. Diese Entscheidung wird basierend auf dem Eingehenden Anforderungsverb und -pfad getroffen. Das Verb gibt an, welcher Http-Anforderungstyp (GET oder POST) durchgeführt wurde, während der Pfad den Speicherort und dateinamen der angeforderten Datei angibt. Wenn also ein HTTP-Handler alle Anforderungen –entweder GET oder POST – für Dateien mit der Erweiterung .scott behandeln soll, fügen wir der Web.config-Datei Folgendes hinzu:

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

Dabei war type der Typ unseres HTTP-Handlers.

Hinweis Beim Registrieren von HTTP-Handlern ist es wichtig, sicherzustellen, dass die vom HTTP-Handler verwendeten Erweiterungen in IIS der ASP.NET-Engine zugeordnet werden. Wenn also in unserem Scott-Beispiel die Erweiterung .scott in IIS nicht der aspnet_isapi.dll ISAPI-Erweiterung zugeordnet ist, führt eine Anforderung für die Datei foo.scott dazu, dass IIS versucht, den Inhalt der Datei foo.scott zurückzugeben. Damit der HTTP-Handler diese Anforderung verarbeiten kann, muss die Erweiterung .scott der ASP.NET-Engine zugeordnet werden. Die ASP.NET-Engine leitet die Anforderung dann ordnungsgemäß an den entsprechenden HTTP-Handler weiter.

Weitere Informationen zum Registrieren von HTTP-Modulen und HTTP-Handlern finden Sie in der <HttpModules-Elementdokumentation> zusammen mit der <HttpHandlers-Elementdokumentation>.

Implementieren des URL-Umschreibens

Url-Umschreibung kann entweder mit ISAPI-Filtern auf IIS-Webserverebene oder mit HTTP-Modulen oder HTTP-Handlern auf ASP.NET-Ebene implementiert werden. Dieser Artikel konzentriert sich auf die Implementierung von URL-Umschreibungen mit ASP.NET, sodass wir uns nicht mit den Besonderheiten der Implementierung von URL-Umschreibungen mit ISAPI-Filtern beschäftigen.

Die Implementierung von URL-Umschreibungen auf ASP.NET Ebene ist über die RewritePath()-Methode der System.Web.HttpContext-Klasse möglich. Die HttpContext-Klasse enthält HTTP-spezifische Informationen zu einer bestimmten HTTP-Anforderung. Bei jeder Anforderung, die von der ASP.NET-Engine empfangen wird, wird für diese Anforderung ein HttpContext-instance erstellt. Diese Klasse verfügt über Eigenschaften wie Anforderung und Antwort, die Zugriff auf die eingehende Anforderung und die ausgehende Antwort ermöglichen. Anwendung und Sitzung, die Zugriff auf Anwendungs- und Sitzungsvariablen ermöglichen; Benutzer, der Informationen über den authentifizierten Benutzer bereitstellt; und andere verwandte Eigenschaften.

Mit der Microsoft® .NET Framework Version 1.0 akzeptiert die RewritePath()-Methode eine einzelne Zeichenfolge, den neuen zu verwendenden Pfad. Intern aktualisiert die RewritePath(string)-Methode der HttpContext-Klasse die Path- und QueryString-Eigenschaften des Request-Objekts. Zusätzlich zu RewritePath(string) enthält die .NET Framework Version 1.1 eine weitere Form der RewritePath()-Methode, die drei Zeichenfolgeneingabeparameter akzeptiert. Diese alternative überladene Form legt nicht nur die Path- und QueryString-Eigenschaften des Request-Objekts fest, sondern auch interne Membervariablen, die zum Berechnen der Werte des Request-Objekts für seine PhysicalPath-, PathInfo- und FilePath-Eigenschaften verwendet werden.

Zum Implementieren des URL-Umschreibens in ASP.NET müssen wir dann ein HTTP-Modul oder einen HTTP-Handler erstellen, der:

  1. Überprüft den angeforderten Pfad, um festzustellen, ob die URL neu geschrieben werden muss.
  2. Schreibt den Pfad bei Bedarf um, indem die RewritePath() -Methode aufgerufen wird.

Stellen Sie sich beispielsweise vor, dass auf unserer Website informationen für jeden Mitarbeiter vorhanden sind, auf die über /info/employee.aspx?empID=employeeID zugegriffen werden kann. Um die URLs "hackfähiger" zu machen, entscheiden wir uns möglicherweise dafür, dass Mitarbeiterseiten über /people/EmployeeName.aspx zugänglich sind. Hier ist ein Fall, in dem wir das URL-Umschreiben verwenden möchten. Das heißt, wenn die Seite /people/ScottMitchell.aspx angefordert wurde, sollten wir die URL so umschreiben, dass stattdessen die Seite /info/employee.aspx?empID=1001 verwendet wurde.

URL-Umschreiben mit HTTP-Modulen

Beim Umschreiben von URLs auf ASP.NET Ebene können Sie entweder ein HTTP-Modul oder einen HTTP-Handler verwenden, um das Umschreiben durchzuführen. Wenn Sie ein HTTP-Modul verwenden, müssen Sie entscheiden, an welchem Punkt während des Lebenszyklus der Anforderung überprüft werden soll, ob die URL neu geschrieben werden muss. Auf den ersten Blick mag dies eine willkürliche Wahl sein, aber die Entscheidung kann sich sowohl auf signifikante als auch auf subtile Weise auf Ihre Anwendung auswirken. Die Wahl, wo das erneute Schreiben durchgeführt werden soll, ist wichtig, da die integrierten ASP.NET HTTP-Module die Eigenschaften des Request-Objekts verwenden, um ihre Aufgaben auszuführen. (Denken Sie daran, dass das Umschreiben des Pfads die Eigenschaftswerte des Request-Objekts ändert.) Diese in Germane integrierten HTTP-Module und die Ereignisse, in die sie eingebunden sind, sind unten aufgeführt:

HTTP-Modul Event Beschreibung
Formsauthenticationmodule Authenticaterequest Bestimmt, ob der Benutzer mithilfe der Formularauthentifizierung authentifiziert wird. Andernfalls wird der Benutzer automatisch zur angegebenen Anmeldeseite umgeleitet.
FileAuthorizationMoudle Authorizerequest Bei Verwendung Windows-Authentifizierung überprüft dieses HTTP-Modul, ob das Microsoft® Windows-Konto® über ausreichende Rechte für die angeforderte Ressource verfügt.
Urlauthorizationmodule Authorizerequest Überprüft, ob der Anforderer auf die angegebene URL zugreifen kann. Die URL-Autorisierung wird über die Autorisierungs <-> und <Speicherortelemente> in der Web.config-Datei angegeben.

Denken Sie daran, dass das BeginRequest-Ereignis vor AuthenticateRequest ausgelöst wird, das vor AuthorizeRequest ausgelöst wird.

Ein sicherer Ort, an dem url rewriting durchgeführt werden kann, ist das BeginRequest-Ereignis . Das bedeutet, dass die URL, wenn sie neu geschrieben werden muss, dies bis zur Ausführung der integrierten HTTP-Module erfolgt ist. Der Nachteil dieses Ansatzes ergibt sich bei der Verwendung der Formularauthentifizierung. Wenn Sie die Formularauthentifizierung bereits verwendet haben, wissen Sie, dass der Benutzer, wenn er eine eingeschränkte Ressource besucht, automatisch zu einer angegebenen Anmeldeseite umgeleitet wird. Nach der erfolgreichen Anmeldung wird der Benutzer zurück zu der Seite gesendet, auf die er zuerst zugreifen wollte.

Wenn das Umschreiben von URL in den BeginRequest - oder AuthenticateRequest-Ereignissen ausgeführt wird, leitet die Anmeldeseite den Benutzer nach der Übermittlung zur neu geschriebenen Seite um. Angenommen, ein Benutzer gibt in sein Browserfenster /people/ScottMitchell.aspx ein, das in /info/employee.aspx?empID=1001 umgeschrieben wird. Wenn die Webanwendung für die Verwendung der Formularauthentifizierung konfiguriert ist, wird beim ersten Besuch des Benutzers /people/ScottMitchell.aspx zuerst die URL in /info/employee.aspx?empID=1001 umgeschrieben. Als Nächstes wird FormsAuthenticationModule ausgeführt, wobei der Benutzer bei Bedarf zur Anmeldeseite umgeleitet wird. Die URL, an die der Benutzer bei erfolgreicher Anmeldung gesendet wird, lautet jedoch /info/employee.aspx?empID=1001, da dies die URL der Anforderung war, als FormsAuthenticationModule ausgeführt wurde.

Ebenso sieht urlAuthorizationModule beim Umschreiben in den BeginRequest- oder AuthenticateRequest-Ereignissen die neu geschriebene URL. Wenn Sie also Standortelemente> in Ihrer Web.config-Datei verwenden<, um die Autorisierung für bestimmte URLs anzugeben, müssen Sie auf die neu geschriebene URL verweisen.

Um diese Feinheiten zu beheben, können Sie die URL-Umschreibung im AuthorizeRequest-Ereignis durchführen. Dieser Ansatz behebt zwar die URL-Autorisierung und Formularauthentifizierungsanomalien, führt jedoch zu einer neuen Falte: Die Dateiautorisierung funktioniert nicht mehr. Bei Verwendung von Windows-Authentifizierung überprüft FileAuthorizationModule, ob der authentifizierte Benutzer über die entsprechenden Zugriffsrechte für den Zugriff auf die bestimmte ASP.NET-Seite verfügt.

Stellen Sie sich vor, eine Gruppe von Benutzern hat keinen Dateizugriff auf Windows-Ebene auf C:\Inetput\wwwroot\info\employee.aspx; Wenn solche Benutzer versuchen, /info/employee.aspx?empID=1001 zu besuchen, erhalten sie einen Autorisierungsfehler. Wenn wir jedoch die URL-Umschreibung in das AuthenticateRequest-Ereignis verschieben, wenn fileAuthorizationModule die Sicherheitseinstellungen überprüft, wird immer noch angenommen, dass die angeforderte Datei /people/ScottMitchell.aspx ist, da die URL noch neu geschrieben werden muss. Daher wird die Überprüfung der Dateiautorisierung erfolgreich ausgeführt, sodass dieser Benutzer den Inhalt der neu geschriebenen URL /info/employee.aspx?empID=1001 anzeigen kann.

Wann sollte das Umschreiben von URL in einem HTTP-Modul durchgeführt werden? Dies hängt davon ab, welche Art der Authentifizierung Sie verwenden. Wenn Sie keine Authentifizierung verwenden, spielt es keine Rolle, ob die URL-Umschreibung in BeginRequest, AuthenticateRequest oder AuthorizeRequest erfolgt. Wenn Sie die Formularauthentifizierung verwenden und keine Windows-Authentifizierung verwenden, platzieren Sie die URL-Umschreibung im AuthorizeRequest-Ereignishandler. Wenn Sie Windows-Authentifizierung verwenden, planen Sie schließlich die URL-Umschreibung während der BeginRequest- oder AuthenticateRequest-Ereignisse.

URL-Umschreibung in HTTP-Handlern

Url-Umschreiben kann auch von einem HTTP-Handler oder einer HTTP-Handlerfactory ausgeführt werden. Denken Sie daran, dass ein HTTP-Handler eine Klasse ist, die für die Generierung des Inhalts für einen bestimmten Anforderungstyp verantwortlich ist. eine HTTP-Handlerfactory ist eine Klasse, die für die Rückgabe eines instance eines HTTP-Handlers zuständig ist, der den Inhalt für einen bestimmten Anforderungstyp generieren kann.

In diesem Artikel wird das Erstellen einer URL-Umschreibungs-HTTP-Handlerfactory für ASP.NET Webseiten behandelt. HTTP-Handlerfactorys müssen die IHttpHandlerFactory-Schnittstelle implementieren, die eine GetHandler()- Methode enthält. Nach der Initialisierung der entsprechenden HTTP-Module bestimmt die ASP.NET-Engine, welcher HTTP-Handler oder welche HTTP-Handlerfactory für die angegebene Anforderung aufgerufen werden soll. Wenn eine HTTP-Handlerfactory aufgerufen werden soll, ruft die ASP.NET-Engine die GetHandler() -Methode der HTTP-Handlerfactory auf, die den HttpContext für die Webanforderung zusammen mit einigen anderen Informationen übergibt. Die HTTP-Handlerfactory muss dann ein -Objekt zurückgeben, das IHttpHandler implementiert, der die Anforderung verarbeiten kann.

Zum Durchführen der URL-Umschreibung über einen HTTP-Handler können wir eine HTTP-Handlerfactory erstellen, deren GetHandler() -Methode den angeforderten Pfad überprüft, um festzustellen, ob er neu geschrieben werden muss. Wenn dies der Fall ist, kann die RewritePath()-Methode des übergebenen HttpContext-Objekts aufgerufen werden, wie zuvor erläutert. Schließlich kann die HTTP-Handlerfactory den HTTP-Handler zurückgeben, der von der GetCompiledPageInstance()-Methode der System.Web.UI.PageParser-Klasse zurückgegeben wird. (Dies ist die gleiche Technik, mit der die integrierte http-Handlerfactory für ASP.NET Webseite, PageHandlerFactory, funktioniert.)

Da alle HTTP-Module vor der Instanziierung der benutzerdefinierten HTTP-Handlerfactory initialisiert wurden, stellt die Verwendung einer HTTP-Handlerfactory die gleichen Herausforderungen vor, wenn die URL-Umschreibung in den letzten Phasen der Ereignisse platziert wird. Die Dateiautorisierung funktioniert nämlich nicht. Wenn Sie sich also auf Windows-Authentifizierung- und Dateiautorisierung verlassen, sollten Sie den HTTP-Modulansatz für das Umschreiben von URLs verwenden.

Im nächsten Abschnitt sehen wir uns das Erstellen einer wiederverwendbaren URL-Umschreibungs-Engine an. Nach der Untersuchung der URL-Umschreibungs-Engine, die im Codedownload dieses Artikels verfügbar ist, werden wir in den verbleibenden zwei Abschnitten die reale Verwendung von URL-Umschreibens untersuchen. Zunächst sehen wir uns an, wie Sie die URL-Umschreibungs-Engine verwenden, und sehen uns ein einfaches Beispiel für das Umschreiben von URLs an. Danach nutzen wir die Leistungsfähigkeit der Umschreibungs-Engine für reguläre Ausdrücke, um wirklich "hackbare" URLs bereitzustellen.

Erstellen einer URL-Umschreibungs-Engine

Um zu veranschaulichen, wie url-Umschreibung in einer ASP.NET Webanwendung implementiert wird, habe ich eine URL-Umschreibungs-Engine erstellt. Diese Umschreibungs-Engine bietet die folgenden Funktionen:

  • Der Entwickler der ASP.NET Seite, der die URL-Umschreibungs-Engine verwendet, kann die Umschreibungsregeln in der Web.config-Datei angeben.
  • Die Umschreibungsregeln können reguläre Ausdrücke verwenden, um leistungsfähige Umschreibungsregeln zu ermöglichen.
  • Url-Umschreiben kann problemlos für die Verwendung eines HTTP-Moduls oder eines HTTP-Handlers konfiguriert werden.

In diesem Artikel wird das Umschreiben von URLs nur mit dem HTTP-Modul untersucht. Informationen dazu, wie HTTP-Handler zum Umschreiben von URL verwendet werden können, finden Sie im Code, der mit diesem Artikel heruntergeladen werden kann.

Angeben von Konfigurationsinformationen für die URL-Umschreibungs-Engine

Sehen wir uns die Struktur der Regeln für das erneute Generieren in der Web.config-Datei an. Zunächst müssen Sie in der Web.config-Datei angeben, ob Sie das URL-Umschreiben mit dem HTTP-Modul oder dem HTTP-Handler durchführen möchten. Im Download enthält die datei Web.config zwei Einträge, die auskommentiert wurden:

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

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

Kommentieren Sie den <HttpModules-Eintrag> aus, um das HTTP-Modul zum Umschreiben zu verwenden. Kommentieren Sie stattdessen den <HttpHandlers-Eintrag> aus, um den HTTP-Handler für das Umschreiben zu verwenden.

Zusätzlich zur Angabe, ob das HTTP-Modul oder der HTTP-Handler zum Umschreiben verwendet wird, enthält die datei Web.config die Regeln für das Umschreiben. Eine Umschreibungsregel besteht aus zwei Zeichenfolgen: dem Muster, nach dem in der angeforderten URL gesucht werden soll, und der Zeichenfolge, durch die das Muster ersetzt werden soll, falls gefunden. Diese Informationen werden in der Web.config-Datei mit der folgenden Syntax ausgedrückt:

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

Jede Rewrite-Regel wird durch ein <RewriterRule-Element> ausgedrückt. Das zu suchde Muster wird vom <LookFor-Element> angegeben, während die Zeichenfolge, durch die das gefundene Muster ersetzt werden soll, <im SentTo-Element> eingegeben wird. Diese Regeln für das erneute Schreiben werden von oben nach unten ausgewertet. Wenn eine Übereinstimmung gefunden wird, wird die URL umgeschrieben, und die Suche durch die Umschreibungsregeln wird beendet.

Beachten Sie beim Angeben von Mustern im <LookFor-Element> , dass reguläre Ausdrücke verwendet werden, um den Abgleich und die Zeichenfolgenersetzung durchzuführen. (Im Folgenden sehen wir uns ein Beispiel aus der Praxis an, das veranschaulicht, wie mit regulären Ausdrücken nach einem Muster gesucht wird.) Da das Muster ein regulärer Ausdruck ist, stellen Sie sicher, dass alle Zeichen mit Escapezeichen versehen werden, die reservierte Zeichen in regulären Ausdrücken sind. (Einige der reservierten Zeichen für reguläre Ausdrücke umfassen: ., ?, ^, $und andere. Diesen kann ein umgekehrter Schrägstrich vorangestellt werden, z. B. \. , um eine Literalperiode abzugleichen.)

URL-Umschreiben mit einem HTTP-Modul

Das Erstellen eines HTTP-Moduls ist so einfach wie das Erstellen einer Klasse, die die IHttpModule-Schnittstelle implementiert. Die IHttpModule-Schnittstelle definiert zwei Methoden:

  • Init(HttpApplication). Diese Methode wird ausgelöst, wenn das HTTP-Modul initialisiert wird. In dieser Methode verknüpfen Sie Ereignishandler mit den entsprechenden HttpApplication-Ereignissen .
  • Dispose(). Diese Methode wird aufgerufen, wenn die Anforderung abgeschlossen und zurück an IIS gesendet wurde. Alle endgültigen Bereinigungen sollten hier ausgeführt werden.

Um das Erstellen eines HTTP-Moduls für das Umschreiben von URLs zu erleichtern, habe ich zunächst eine abstrakte Basisklasse erstellt, BaseModuleRewriter. Diese Klasse implementiert IHttpModule. Im Init()-Ereignis wird das AuthorizeRequest-Ereignis von HttpApplication mit der BaseModuleRewriter_AuthorizeRequest-Methode verbunden. Die BaseModuleRewriter_AuthorizeRequest-Methode ruft die Rewrite() -Methode der Klasse auf, die den angeforderten Path zusammen mit dem HttpApplication-Objekt übergibt, das an die Init() -Methode übergeben wurde. Die Rewrite()-Methode ist abstrakt, was bedeutet, dass die Rewrite()-Methode in der BaseModuleRewriter-Klasse keinen Methodentext aufweist. Stattdessen muss die von BaseModuleRewriter abgeleitete Klasse diese Methode überschreiben und einen Methodentext bereitstellen.

Nachdem diese Basisklasse eingerichtet ist, müssen wir jetzt nur noch eine von BaseModuleRewriter abgeleitete Klasse erstellen, die Rewrite() überschreibt und die URL-Umschreibungslogik dort ausführt. Der Code für BaseModuleRewriter wird unten gezeigt.

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);
}

Beachten Sie, dass die BaseModuleRewriter-Klasse url-Umschreibung im AuthorizeRequest-Ereignis ausführt. Wenn Sie Windows-Authentifizierung mit Dateiautorisierung verwenden, müssen Sie dies ändern, sodass das URL-Umschreiben entweder in den BeginRequest- oder AuthenticateRequest-Ereignissen ausgeführt wird.

Die ModuleRewriter-Klasse erweitert die BaseModuleRewriter-Klasse und ist für die Durchführung des tatsächlichen URL-Umschreibens verantwortlich. ModuleRewriter enthält eine einzelne überschriebene Methode – Rewrite() – wie unten gezeigt:

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

Die Rewrite()- Methode beginnt mit dem Abrufen des Satz von Umschreibungsregeln aus der Web.config-Datei. Anschließend durchlaufen sie die Regeln für das erneute Generieren nacheinander, und für jede Regel greift sie die LookFor-Eigenschaft ab und verwendet einen regulären Ausdruck, um zu bestimmen, ob eine Übereinstimmung in der angeforderten URL gefunden wird.

Wenn eine Übereinstimmung gefunden wird, wird ein regulärer Ausdruck für den angeforderten Pfad durch den Wert der SendTo-Eigenschaft ersetzt. Diese ersetzte URL wird dann an die RewriterUtils.RewriteUrl()- Methode übergeben. RewriterUtils ist eine Hilfsklasse, die einige statische Methoden bereitstellt, die sowohl vom URL-Umschreiben des HTTP-Moduls als auch vom HTTP-Handler verwendet werden. Die RewriterUrl()-Methode ruft einfach die RewriteUrl()-Methode des HttpContext-Objekts auf.

Hinweis Möglicherweise haben Sie bemerkt, dass beim Ausführen der Übereinstimmung und Ersetzung des regulären Ausdrucks ein Aufruf von RewriterUtils.ResolveUrl() erfolgt. Diese Hilfsmethode ersetzt einfach alle Instanzen von ~ in der Zeichenfolge durch den Wert des Anwendungspfads.

Der gesamte Code für die URL-Umschreibungs-Engine steht in diesem Artikel zum Download zur Verfügung. Wir haben die meisten deutschen Teile untersucht, aber es gibt auch andere Komponenten, z. B. Klassen zum Deserialisieren der XML-formatierten Umschreibregeln in der Web.config-Datei in ein -Objekt sowie die HTTP-Handlerfactory für das URL-Umschreiben. In den verbleibenden drei Abschnitten dieses Artikels werden die realen Verwendungen von URL-Umschreibungen untersucht.

Durchführen eines einfachen URL-Umschreibens mit der URL-Umschreibungs-Engine

Um die URL-Umschreibungs-Engine in Aktion zu veranschaulichen, erstellen wir eine ASP.NET Webanwendung, die einfaches URL-Umschreiben verwendet. Stellen Sie sich vor, wir arbeiten für ein Unternehmen, das verschiedene Produkte online verkauft. Diese Produkte sind in die folgenden Kategorien unterteilt:

Kategorie-ID Kategoriename
1 Getränke
2 Gewürze
3 Confections
4 Dairy Products
... ...

Angenommen, wir haben bereits eine ASP.NET Webseite namens ListProductsByCategory.aspx erstellt, die einen Kategorie-ID-Wert in der Abfragezeichenfolge akzeptiert und alle Produkte anzeigt, die zu dieser Kategorie gehören. Benutzer, die unsere Getränke zum Verkauf anzeigen möchten, würden also ListProductsByCategory.aspx besuchen? CategoryID=1, während Benutzer, die unsere Molkereiprodukte anzeigen möchten, ListProductsByCategory.aspx besuchen würden? CategoryID=4. Angenommen, wir verfügen über eine Seite namens ListCategories.aspx, die die Kategorien der zum Verkauf bestimmten Produkte auflistet.

Dies ist eindeutig ein Fall für das Umschreiben von URLs, da die URLs, die einem Benutzer angezeigt werden, für den Benutzer keine Bedeutung haben und auch keine "Hackbarkeit" bieten. Verwenden Wir stattdessen das URL-Umschreiben, damit beim Besuch von /Products/Beverages.aspx seine URL in ListProductsByCategory.aspx umgeschrieben wird? CategoryID=1. Dies kann mit der folgenden URL-Umschreibungsregel in der Web.config-Datei erreicht werden:

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

Wie Sie sehen können, sucht diese Regel, um festzustellen, ob der vom Benutzer angeforderte Pfad /Products/Beverages.aspx war. Wenn dies der Fehler war, wird die URL in /ListProductsByCategory.aspx umgeschrieben? CategoryID=1.

Hinweis Beachten Sie, dass das <LookFor-Element> den Punkt in Beverages.aspx nicht enthält. Dies liegt daran, dass der <LookFor-Wert> in einem regulären Ausdrucksmuster verwendet wird, und punkt ein Sonderzeichen in regulären Ausdrücken ist, was bedeutet, dass "mit einem beliebigen Zeichen übereinstimmen", was bedeutet, dass beispielsweise eine URL von /Products/BeveragesQaspx übereinstimmen würde. Durch Die Kapselung des Punkts (mit \.) geben wir an, dass wir mit einem Literalzeitraum und nicht mit einem alten Zeichen übereinstimmen möchten.

Wenn diese Regel gilt, werden die Getränke zum Verkauf angezeigt, wenn ein Benutzer /Products/Beverages.aspx besucht. Abbildung 3 zeigt einen Screenshot eines Browsers, der /Products/Beverages.aspx besucht. Beachten Sie, dass in der Adressleiste des Browsers die URL /Products/Beverages.aspx lautet, der Benutzer jedoch tatsächlich den Inhalt von ListProductsByCategory.aspx sieht? CategoryID=1. (Tatsächlich ist nicht einmal eine Datei /Products/Beverages.aspx auf dem Webserver vorhanden!)

ms972974.urlrewriting_fig03(en-us,MSDN.10).gif

Abbildung 3. Anfordern einer Kategorie nach dem Umschreiben der URL

Ähnlich wie /Products/Beverages.aspx fügen wir als Nächstes Regeln für das Umschreiben für die anderen Produktkategorien hinzu. Dies beinhaltet lediglich das Hinzufügen zusätzlicher <RewriterRule-Elemente> innerhalb des <Rules-Elements> in der Web.config-Datei. In der Web.config-Datei im Download finden Sie den vollständigen Satz von Umschreibungsregeln für die Demo.

Um die URL "hackbarer" zu machen, wäre es schön, wenn ein Benutzer einfach die Beverages.aspx von /Products/Beverages.aspx abhacken und eine Liste der Produktkategorien anzeigen könnte. Auf den ersten Blick kann dies als triviale Aufgabe erscheinen: Fügen Sie einfach eine Umschreibungsregel hinzu, die /Products/ /ListCategories.aspx zuordnet. Es gibt jedoch eine feine Subtilität: Sie müssen zuerst ein Verzeichnis /Products/ erstellen und eine leere Default.aspx-Datei im Verzeichnis /Products/ hinzufügen.

Um zu verstehen, warum diese zusätzlichen Schritte ausgeführt werden müssen, denken Sie daran, dass sich die URL-Umschreibungs-Engine auf ASP.NET Ebene befindet. Das heißt, wenn die ASP.NET-Engine nie die Möglichkeit erhält, die Anforderung zu verarbeiten, kann die URL-Umschreibungs-Engine die eingehende URL nicht überprüfen. Denken Sie außerdem daran, dass IIS eingehende Anforderungen nur dann an die ASP.NET-Engine weitergibt, wenn die angeforderte Datei über eine entsprechende Erweiterung verfügt. Wenn also ein Benutzer /Products/ besucht, wird bei IIS keine Dateierweiterung angezeigt, sodass das Verzeichnis überprüft wird, ob eine Datei mit einem der Standarddateinamen vorhanden ist. (Default.aspx, Default.htm, Default.asp usw. Diese Standarddateinamen werden im Dialogfeld IIS-Verwaltung auf der Registerkarte Dokumente des Dialogfelds Webservereigenschaften definiert.) Wenn das Verzeichnis /Products/ nicht vorhanden ist, gibt IIS natürlich einen HTTP 404-Fehler zurück.

Daher müssen wir das Verzeichnis /Products/ erstellen. Darüber hinaus müssen Wir eine einzelne Datei in diesem Verzeichnis erstellen, Default.aspx. Wenn ein Benutzer /Products/ besucht, überprüft IIS das Verzeichnis, überprüft, dass eine Datei mit dem Namen Default.aspx vorhanden ist, und übergibt dann die Verarbeitung an die ASP.NET-Engine. Unser URL-Rewriter erhält dann einen Riss beim Umschreiben der URL.

Nachdem Sie das Verzeichnis und die Datei Default.aspx erstellt haben, fügen Sie dem Rules-Element> die folgende Umschreibungsregel< hinzu:

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

Mit dieser Regel wird beim Besuch von /Products/ oder /Products/Default.aspx die Liste der Produktkategorien angezeigt, die in Abbildung 4 dargestellt ist.

ms972974.urlrewriting_fig04(en-us,MSDN.10).gif

Abbildung 4. Hinzufügen von "Hackability" zur URL

Behandeln von Postbacks

Wenn die URLs, die Sie neu schreiben, ein serverseitiges Webformular enthalten und Postbacks ausführen, wird die zugrunde liegende URL verwendet, wenn das Formular zurückgibt. Das heißt, wenn unser Benutzer in seinen Browser /Products/Beverages.aspx eingibt, wird er weiterhin in der Adressleiste seines Browsers /Products/Beverages.aspx angezeigt, aber der Inhalt für ListProductsByCategory.aspx wird angezeigt? CategoryID=1. Wenn ListProductsByCategory.aspx ein Postback ausführt, wird der Benutzer zurück an ListProductsByCategory.aspx gesendet? CategoryID=1, nicht /Products/Beverages.aspx. Dadurch wird nichts unterbrochen, aber es kann aus der Perspektive des Benutzers beunruhigend sein, wenn sich die URL beim Klicken auf eine Schaltfläche plötzlich ändert.

Der Grund dafür ist, dass das Webformular beim Rendern des Webformulars sein Aktionsattribute explizit auf den Wert des Dateipfads im Request-Objekt festlegt. Zum Rendern des Webformulars wurde die URL natürlich von /Products/Beverages.aspx in ListProductsByCategory.aspx umgeschrieben? CategoryID=1, was bedeutet, dass das Request-Objekt meldet, dass der Benutzer ListProductsByCategory.aspx besucht? CategoryID=1. Dieses Problem kann behoben werden, indem das serverseitige Formular einfach kein Aktionsattribute rendert. (Browser werden standardmäßig postback verwendet, wenn das Formular kein Aktionsattribute enthält.)

Leider erlaubt das Webformular nicht, ein Aktionsattribute explizit anzugeben, und es ermöglicht es Ihnen auch nicht, eine Eigenschaft festzulegen, um das Rendering des Aktionsattributes zu deaktivieren. Stattdessen müssen wir die System.Web.HtmlControls.HtmlForm-Klasse selbst erweitern, indem wir die RenderAttribute() -Methode außer Kraft setzen und explizit angeben, dass das Aktionsattribut nicht gerendert wird.

Dank der Kraft der Vererbung können wir die gesamte Funktionalität der HtmlForm-Klasse gewinnen und müssen nur wenige Codezeilen hinzufügen, um das gewünschte Verhalten zu erzielen. Der vollständige Code für die benutzerdefinierte Klasse ist unten dargestellt:

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);
     }
  }
}

Der Code für die überschriebene RenderAttributes()-Methode enthält einfach den exakten Code aus der RenderAttributes()-Methode der HtmlForm-Klasse, ohne jedoch das Aktionsattribut festzulegen. (Ich habe den Reflector von Lutz Roeder verwendet, um den Quellcode der HtmlForm-Klasse anzuzeigen.)

Nachdem Sie diese Klasse erstellt und kompiliert haben, fügen Sie sie zum Ordner Verweise der Webanwendung hinzu, um sie in einer ASP.NET-Webanwendung zu verwenden. Um sie dann anstelle der HtmlForm-Klasse zu verwenden, fügen Sie einfach Folgendes oben auf Ihrer ASP.NET-Webseite hinzu:

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

Ersetzen Sie dann, wenn Sie haben <form runat="server">, dies durch:

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

und ersetzen Sie das schließende </form> Tag durch:

</skm:Form>

Sie können diese benutzerdefinierte Web Form-Klasse in Aktion in ListProductsByCategory.aspx sehen, die im Download dieses Artikels enthalten ist. Im Download enthalten ist auch ein Visual Studio .NET-Projekt für das aktionslose Webformular.

Hinweis Wenn die URL, in die Sie umschreiben, kein Postback ausführt, ist es nicht erforderlich, diese benutzerdefinierte Web Form-Klasse zu verwenden.

Erstellen wirklich "hackbarer" URLs

Die im vorherigen Abschnitt gezeigte einfache URL-Umschreibung hat gezeigt, wie einfach die URL-Umschreibungs-Engine mit neuen Umschreibungsregeln konfiguriert werden kann. Die wahre Leistungsfähigkeit der Umschreibungsregeln scheint jedoch, wenn reguläre Ausdrücke verwendet werden, wie wir in diesem Abschnitt sehen werden.

Blogs werden in diesen Tagen immer beliebter, und es scheint, dass jeder seinen eigenen Blog hat. Wenn Sie mit Blogs nicht vertraut sind, sind dies häufig aktualisierte persönliche Seiten, die in der Regel als Online-Journal dienen. Die meisten Blogger schreiben einfach über ihre alltäglichen Ereignisse, andere konzentrieren sich auf das Bloggen über ein bestimmtes Thema, z. B. Filmkritiken, ein Sportteam oder eine Computertechnologie.

Je nach Autor werden Blogs mehrmals täglich auf einmal wöchentlich aktualisiert. In der Regel werden auf der Blog-Startseite die neuesten 10 Einträge angezeigt, aber praktisch alle Bloggingsoftware bietet ein Archiv, über das Besucher ältere Beiträge lesen können. Blogs sind eine großartige Anwendung für "hackbare" URLs. Stellen Sie sich vor, Sie haben sich beim Durchsuchen der Archive eines Blogs unter der URL /2004/02/14.aspx gefunden. Wären Sie schrecklich überrascht, wenn Sie die Beiträge vom 14. Februar 2004 lesen würden? Darüber hinaus können Sie alle Beiträge für Februar 2004 anzeigen, in diesem Fall könnten Sie versuchen, die URL auf /2004/02/ zu hacken. Um alle 2004-Beiträge anzuzeigen, können Sie versuchen, /2004/ zu besuchen.

Wenn Sie einen Blog verwalten, wäre es schön, Ihren Besuchern diese Ebene der URL -Hackbarkeit bereitzustellen. Obwohl viele Blog-Engines diese Funktionalität bereitstellen, sehen wir uns an, wie dies mithilfe des URL-Umschreibens erreicht werden kann.

Zunächst benötigen wir eine einzelne ASP.NET Webseite, auf der Blogeinträge nach Tag, Monat oder Jahr angezeigt werden. Angenommen, wir haben eine solche Seite, ShowBlogContent.aspx, die Abfragezeichenfolgenparameter Jahr, Monat und Tag einnimmt. Um die Beiträge für den 14. Februar 2004 anzuzeigen, können wir ShowBlogContent.aspx?year=2004&month=2&day=14 besuchen. Um alle Beiträge für Februar 2004 anzuzeigen, besuchen Wir ShowBlogContent.aspx?year=2004&month=2. Um schließlich alle Beiträge für das Jahr 2004 anzuzeigen, navigieren wir zu ShowBlogContent.aspx?year=2004. (Den Code für ShowBlogContent.aspx finden Sie im Download dieses Artikels.)

Wenn ein Benutzer also /2004/02/14.aspx besucht, müssen wir die URL in ShowBlogContent.aspx?year=2004&month=2&day=14 umschreiben. Alle drei Fälle– wenn die URL ein Jahr, einen Monat und einen Tag angibt; wenn die URL nur das Jahr und den Monat angibt; und wenn die URL nur das Ja angibt, können drei Rewrite-Regeln verwendet werden:

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

Diese Umschreibungsregeln veranschaulichen die Leistungsfähigkeit regulärer Ausdrücke. In der ersten Regel suchen wir nach einer URL mit dem Muster (\d{4})/(\d{2})/(\d)/(\d{2})\.aspx. Im einfachen Englischen entspricht dies einer Zeichenfolge mit vier Ziffern gefolgt von einem schrägen Schrägstrich gefolgt von zwei Ziffern gefolgt von einem schrägen Schrägstrich, gefolgt von zwei Ziffern gefolgt von .aspx. Die Klammern um jede Zifferngruppierung sind von entscheidender Bedeutung– sie ermöglicht es uns, auf die übereinstimmenden Zeichen in diesen Klammern in der entsprechenden <SendTo-Eigenschaft> zu verweisen. Insbesondere können wir auf die übereinstimmenden Klammergruppierungen mit $1, $2 und $3 für die erste, zweite und dritte Klammergruppierung verweisen.

Hinweis Da die Web.config Datei XML-formatiert ist, müssen Zeichen wie &, <und > im Textteil eines Elements mit Escapezeichen versehen werden. In der ersten Regel <wird das SendTo-Element>& mit escaped to &amp;. In SendTo> der zweiten Regel< wird eine alternative Technik verwendet– mithilfe eines <![ CDATA[...]]> -Element, müssen die darin enthaltenen Inhalte nicht mit Escapezeichen versehen werden. Beide Ansätze sind akzeptabel und erreichen das gleiche Ende.

Die Abbildungen 5, 6 und 7 zeigen, wie die URL in Aktion umgeschrieben wird. Die Daten werden tatsächlich aus meinem Blog http://ScottOnWriting.NETabgerufen. In Abbildung 5 sind die Beiträge für den 7. November 2003 dargestellt. in Abbildung 6 sind alle Beiträge für November 2003 dargestellt; Abbildung 7 zeigt alle Beiträge für 2003.

ms972974.urlrewriting_fig05(en-us,MSDN.10).gif

Abbildung 5. Beiträge für den 7. November 2003

ms972974.urlrewriting_fig06(en-us,MSDN.10).gif

Abbildung 6. Alle Beiträge für November 2003

ms972974.urlrewriting_fig07(en-us,MSDN.10).gif

Abbildung 7. Alle Beiträge für 2003

Hinweis Die URL-Umschreibungs-Engine erwartet ein Muster für reguläre Ausdrücke in den <LookFor-Elementen> . Wenn Sie mit regulären Ausdrücken nicht vertraut sind, sollten Sie einen früheren Artikel von mir lesen, Eine Einführung in reguläre Ausdrücke. Außerdem ist RegExLib.com ein großartiger Ort, um häufig verwendete reguläre Ausdrücke in die Hand zu bekommen, sowie ein Repository zum Freigeben eigener erstellter regulärer Ausdrücke.

Erstellen der erforderlichen Verzeichnisstruktur

Wenn eine Anforderung für /2004/03/19.aspx eingeht, notiert IIS die .aspx-Erweiterung und leitet die Anforderung an die ASP.NET-Engine weiter. Wenn die Anforderung die Pipeline der ASP.NET-Engine durchläuft, wird die URL in ShowBlogContent.aspx?year=2004&month=03&day=19 umgeschrieben, und dem Besucher werden diese Blogeinträge für den 19. März 2004 angezeigt. Aber was geschieht, wenn der Benutzer zu /2004/03/ navigiert? Sofern kein Verzeichnis /2004/03/ vorhanden ist, gibt IIS den Fehler 404 zurück. Darüber hinaus muss in diesem Verzeichnis eine Default.aspx-Seite vorhanden sein, damit die Anforderung an die ASP.NET-Engine übergeben wird.

Bei diesem Ansatz müssen Sie also manuell ein Verzeichnis für jedes Jahr erstellen, in dem Blogeinträge vorhanden sind, mit einer Default.aspx-Seite im Verzeichnis. Darüber hinaus müssen Sie in jedem Jahresverzeichnis zwölf weitere Verzeichnisse (01, 02, ..., 12) manuell mit einer Default.aspx-Datei erstellen. (Denken Sie daran, dass wir in der vorherigen Demo dasselbe tun mussten– ein Verzeichnis /Products/ mit einer Default.aspx-Datei hinzufügen, damit beim Besuch von /Products/ listCategories.aspx richtig angezeigt wurde.)

Natürlich kann das Hinzufügen einer solchen Verzeichnisstruktur ein Problem sein. Eine Problemumgehung für dieses Problem besteht darin, dass alle eingehenden IIS-Anforderungen der ASP.NET-Engine zugeordnet werden. Auf diese Weise gibt IIS die Anforderung auch dann an die ASP.NET-Engine weiter, wenn kein Verzeichnis /2004/03/ vorhanden ist. Wenn Sie diesen Ansatz verwenden, ist die ASP.NET-Engine jedoch für die Verarbeitung aller Arten von eingehenden Anforderungen an den Webserver verantwortlich, einschließlich Bildern, CSS-Dateien, externen JavaScript-Dateien, Macromedia Flash Dateien usw.

Eine gründliche Erläuterung der Behandlung aller Dateitypen geht weit über den Rahmen dieses Artikels hinaus. Ein Beispiel für eine ASP.NET-Webanwendung, die diese Technik verwendet, finden Sie unter . Text, eine Open-Source-Blog-Engine. . Text kann so konfiguriert werden, dass alle Anforderungen der ASP.NET-Engine zugeordnet werden. Es kann die Bereitstellung aller Dateitypen mithilfe eines benutzerdefinierten HTTP-Handlers verarbeiten, der weiß, wie typische statische Dateitypen (Bilder, CSS-Dateien usw.) bereitgestellt werden.

Zusammenfassung

In diesem Artikel haben wir uns mit der RewriteUrl()-Methode der HttpContext-Klasse auf ASP.NET-Ebene befasst. Wie wir gesehen haben, aktualisiert RewriteUrl() die Anforderungseigenschaft von httpContext und aktualisiert, welche Datei und welcher Pfad angefordert wird. Der Nettoeffekt besteht darin, dass er aus Sicht des Benutzers eine bestimmte URL aufruft, aber tatsächlich eine andere URL auf der Webserverseite angefordert wird.

URLs können entweder in einem HTTP-Modul oder in einem HTTP-Handler umgeschrieben werden. In diesem Artikel haben wir die Verwendung eines HTTP-Moduls zum Durchführen des Umschreibens untersucht und die Konsequenzen der Durchführung des Umschreibens in verschiedenen Phasen der Pipeline untersucht.

Natürlich kann die URL-Umschreibung bei ASP.NET-Ebene nur erfolgen, wenn die Anforderung erfolgreich von IIS an die ASP.NET-Engine übergeben wurde. Dies tritt natürlich auf, wenn der Benutzer eine Seite mit einer ASPX-Erweiterung anfordert. Wenn Sie jedoch möchten, dass die Person eine URL eingeben kann, die möglicherweise nicht vorhanden ist, aber lieber auf eine vorhandene ASP.NET-Seite umgeschrieben wird, müssen Sie entweder Pseudoverzeichnisse und Default.aspx-Seiten erstellen oder IIS so konfigurieren, dass alle eingehenden Anforderungen blind an die ASP.NET-Engine weitergeleitet werden.

ASP.NET: Tipps, Tutorials und Code

Microsoft ASP.NET Coding Strategies with the Microsoft ASP.NET Team

Wichtige ASP.NET mit Beispielen in C#

Konsultierte Werke

Url-Umschreibung ist ein Thema, das sowohl für ASP.NET als auch für konkurrierende serverseitige Webtechnologien große Aufmerksamkeit erhalten hat. Der Apache-Webserver stellt für instance ein Modul zum Umschreiben von URLs mit dem Namen mod_rewrite bereit. mod_rewrite ist eine robuste Umschreibungs-Engine, die Regeln für das Umschreiben basierend auf Bedingungen wie HTTP-Headern und Servervariablen sowie Umschreibungsregeln bereitstellt, die reguläre Ausdrücke verwenden. Weitere Informationen zu mod_rewrite finden Sie unter A User's Guide to URL Rewriting with the Apache Web Server ( A User es Guide to URL Rewriting with the Apache Web Server).

Es gibt eine Reihe von Artikeln zum Umschreiben von URLs mit ASP.NET. Rewrite.NET: Eine URL-Rewriting-Engine für .NET untersucht die Erstellung einer URL-Umschreibungs-Engine, die die Regeln für reguläre Ausdrücke mod_rewrite imitiert. Url Rewriting Mit ASP.NET bietet auch eine gute Übersicht über ASP. DIE URL-Umschreibungsfunktionen von NET. Ian Griffiths hat einen Blogeintrag über einige der Einschränkungen im Zusammenhang mit der URL-Umschreibung mit ASP.NET, z. B. das in diesem Artikel behandelte Postbackproblem. Sowohl Fabrice Marguerie (mehr lesen) als auch Jason Salas (mehr lesen) haben Blog-Ganze über die Verwendung von URL-Umschreibens, um die Suchmaschinenplatzierung zu fördern.

 

Über den Autor

Scott Mitchell, Autor von fünf Büchern und Gründer von 4GuysFromRolla.com, arbeitet seit fünf Jahren mit Microsoft-Webtechnologien. Scott arbeitet als unabhängiger Berater, Trainer und Autor. Er ist unter mitchell@4guysfromrolla.com oder über seinen Blog zu erreichen, der unter http://ScottOnWriting.NETzu finden ist.

© Microsoft Corporation. Alle Rechte vorbehalten.