Einer der Gründe, weshalb ich das ASP.NET MVC Framework mag, ist die durchgehende Verwendung der sehr flexiblen Routing Engine. In einem MVC Projekt ist das Addressierungsschema komplett vom physikalischen Filesystem getrennt. So lassen sich einfach Applikationen im REST Stil bauen. Adressen wie “http://applikation/Kunde/42″ oder “http://applikation/Kunde/42/Bestellungen” sind auch deutlich SEO freundlicher als die direkte Adressierung auf ein physikalisch vorhandenes File.
Die Routing Engine ist jedoch nicht Bestandteil des MVC Frameworks, sondern wurde mit .NET 3.5 SP1 eingeführt. Somit kann sie auch in einem WebForm Projekt verwendet werden. Der Aufwand hält sich dabei in Grenzen, das ganze ist recht schnell umgesetzt.
Teil 1 dieses Artikels zeigt die Konfiguration der Routing Engine in einer WebForms Applikation und das Anlegen eigener Routen. In einem zweiten Teil werden dann die Security Einstellungen betrachtet.
Konfiguration der WebForms Applikation
Um die Routing Engine nutzen zu können, müssen im Projekt zwei Verweise gesetzt werden: System.Web.Routing und System.Web.Abstractions sind beide im GAC installiert, sie können einfach über “Add Reference” hinzugefügt werden.
Danach muss das Routing Modul im web.config in die Request Pipeline konfiguriert werden. Unter IIS 6 geschieht dies wie folgt:
<httpModules>
...
<add name="RoutingModule"
type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
Wenn IIS 7 verwendet wird, müssen die folgenden Einträge gemacht werden:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
...
<add name="UrlRoutingModule"
type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35&" />
...
</modules>
<handlers>
...
<add name="UrlRoutingHandler"
preCondition="integratedMode"
verb="*" path="UrlRouting.axd"
type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
...
</handlers>
</system.webServer>
Wenn die Zielumgebung bekannt ist, kann auf die eine Variante verzichtet werden, Einträge für IIS 6 werden allerdings vom IIS 7 ignoriert, und umgekehrt auch, so dass getrost beide Varianten eingetragen werden können.
Konfiguration der Routen
Falls nicht bereits vorhanden, wird eine global.asax Datei zum Projekt hinzugefügt. In dessen Application_Start Event können die Routen eingetragen werden. Eine Route hat immer einen eindeutigen Namen, definiert ein Adressenmuster und legt fest, von welchem Handler Anfragen an diese Adresse bearbeitet werden:
RouteTable.Routes.Add("Customers", new Route("customer/", new PageRouteHandler("~/Customers/Customers.aspx")));
RouteTable.Routes.Add("CustomerDetails", new Route("customer/{id}", new PageRouteHandler("~/Customers/CustomerDetails.aspx")));
Dies erstellt zwei Einträge in der Routing Tabelle. Der zweite Eintrag verwendet einen Parameter “id”, wenn also ein Request in der Form “customer/42″ eintrifft, wird dieser Eintrag verwendet.
Zu beachten ist, dass beim Eintreffen eines Requests diese Routing Tabelle von oben nach unten abgearbeitet wird, und der erste zur Request Adresse passende Eintrag verwendet wird. Nachfolgende Einträge werden ignoriert.
Nun muss der PageRouteHandler angelegt werden, welcher diese Anfragen bearbeiten kann. Dies ist eine Klasse, welche das IRouteHandler Interface implementiert:
public class PageRouteHandler : IRouteHandler
{
private readonly string _virtualPath;
public PageRouteHandler(string virtualPath)
{
_virtualPath = virtualPath;
}
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var page = BuildManager.CreateInstanceFromVirtualPath(_virtualPath, typeof(Page));
return (IHttpHandler)page;
}
}
Dies ist bereits alles, was benötigt wird, um eigene Routen zu definieren und an Webforms weiterzuleiten. Jedoch gelangt im zweiten Fall, wenn eine ID übergeben wird, diese nicht bis zum Webform. Dies kann gelöst werden, indem innerhalb des Routing Handlers die Routing Daten des RequestContext an das Webform weitergeleitet werden. Die Methode GetHttpHandler sieht also wie folgt aus:
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var page = BuildManager.CreateInstanceFromVirtualPath(_virtualPath, typeof(Page));
var queryString = new StringBuilder("?");
foreach (var rdv in requestContext.RouteData.Values)
{
queryString.Append(requestContext.HttpContext.Server.UrlEncode(rdv.Key));
queryString.Append("=");
queryString.Append(requestContext.HttpContext.Server.UrlEncode(rdv.Value.ToString()));
queryString.Append("&");
}
queryString.Remove(queryString.Length - 1, 1);
HttpContext.Current.RewritePath(string.Concat(_virtualPath, queryString));
return (IHttpHandler)page;
}