Umstieg auf UrlRewritingNet.UrlRewrite - neue Rewrites via Code hinzufügen

Written on March 08, 2006

Nachdem ich bisher mit dem UrlRewriting-Modul (mit kleinen Anpassungen) von Fabrice Marguerie gearbeitet habe, bin ich heute auf UrlRewritingNet.UrlRewrite von Thomas und Albert umgestiegen.

Der Hauptgrund für den Umstieg war, dass UrlRewritingNet.UrlRewrite ein echtes ASP.NET 2.0 Modul ist, was sich z.B. dadurch äußert, dass es die web.config nicht als XML parsed, sondern z.B. mit ConfigurationSection und ConfigurationElement aus dem .NET 2.0 Framework arbeitet.

Ein Feature, das ich an UrlRewritingNet.UrlRewrite momentan noch vermisse (Albert gelobt aber Besserung ;-)), ist das Hinzufügen von neuen Rewrite-Definitionen.

Deshalb hier ein Snippet, wie man das dennoch relativ straight selbst implementieren kann:

Voraussetzung hierfür ist, dass man das Attribut configSource in der ConfigurationSection "urlrewritingnet" setzt:

<urlrewritingnet configSource="rewrites.config" />

und somit ein Xml-File hat, das man leicht lesen und schreiben kann (Berechtigungen voraussgesetzt).

Das File könnte dann wie folgt aussehen:

<urlrewritingnet rewriteOnlyVirtualUrls="true" compileRegex="true" contextItemsPrefix="QueryString" xmlns="http://www.urlrewriting.net/schemas/config/2006/01">
  <rewrites>
    <add virtualUrl="~/anfahrt/default.aspx" destinationUrl="~/Default.aspx?ContentID=95" ignoreCase="true" rewriteUrlParameter="ExcludeFromClientQueryString" />
    <add virtualUrl="~/kontakt/default.aspx" destinationUrl="~/Default.aspx?ContentID=79" ignoreCase="true" rewriteUrlParameter="ExcludeFromClientQueryString" />
  </rewrites>
</urlrewritingnet>

Um nun eine neue Rewrite-Definition hinzuzufügen, ist folgender Code notwendig:

using System;
using System.Data;
using System.Configuration;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml;
using System.Xml.XPath;

/// <summary>
/// Summary description for UrlRewritingHelper
/// </summary>
public class UrlRewritingHelper {
    public UrlRewritingHelper() {

    }

    /// <summary>
    /// Fügt eine neue UrlRewriting-Definition an die bestehenden Defintionen an.
    /// </summary>
    /// <param name="ConfigSource">Gibt den Pfad zur Definitionsdatei an.</param>
    /// <param name="VirtualUrl">Ein regulärer Ausdruck auf den geprüft wird und eine Ersetzung durch destinationUrl gemacht.</param>
    /// <param name="DestinationUrl">Ein regulärer Ersetzungsausdruck der die eigentliche Zielseite beschreibt.</param>
    /// <param name="RewriteUrlParameter">Legt die Behandlung von Url-Parametern fest, siehe http://www.urlrewriting.net/de/Config.aspx</param>
    /// <param name="IgnoreCase">Bei vergleichen der Request-Url mit virtualUrl wird die Groß- und Kleinschreibung ignoriert. </param>
    /// <param name="IsPermanent">Es wird eine permanete Weiterleitung für die Url inkl. des Http-Status Codes 301 an den Browser zurückgeliefert.</param>
    public static void AddRewrite(string ConfigSource, string VirtualUrl, string DestinationUrl, RewriteUrlParameter RewriteUrlParameter, bool IgnoreCase, bool IsPermanent) {

        // neues Xml-Dokument erzeugen
        XmlDocument doc = new XmlDocument();

        // und bestehende Rewrites laden
        doc.Load(ConfigSource);

        // XPathNavigator zum Bearbeiten des Xml-Dokuments erzeugen
        XPathNavigator xml = doc.CreateNavigator();

        // "Cursor" an die richtige...
        xml.MoveToChild("urlrewritingnet", "http://www.urlrewriting.net/schemas/config/2006/01");

        // ...Position im Xml-Dokument setzen
        xml.MoveToChild("rewrites", "http://www.urlrewriting.net/schemas/config/2006/01");

        // neue Rewrite-Definition erstellen
        StringBuilder sbRewrite = new StringBuilder("<add ");

        // VirtualUrl-Definition hinzufügen
        sbRewrite.Append("virtualUrl=\"");
        sbRewrite.Append(VirtualUrl);
        sbRewrite.Append("\" ");

        // DestinationUrl-Definition hinzufügen
        sbRewrite.Append("destinationUrl=\"");
        sbRewrite.Append(DestinationUrl);
        sbRewrite.Append("\" ");

        // RewriteUrlParameter-Definition hinzufügen
        sbRewrite.Append("rewriteUrlParameter=\"");
        sbRewrite.Append(RewriteUrlParameter.ToString());
        sbRewrite.Append("\" ");

        // IgnoreCase-Definition hinzufügen
        sbRewrite.Append("ignoreCase=\"");
        sbRewrite.Append(IgnoreCase.ToString());
        sbRewrite.Append("\" ");

        // IsPermanent-Definition hinzufügen
        sbRewrite.Append("permanent=\"");
        sbRewrite.Append(IsPermanent.ToString());
        sbRewrite.Append("\" ");

        // neue Definition abschließen
        sbRewrite.Append(" />");

        // neue Definition an bestehende Definitionen anhängen
        xml.AppendChild(sbRewrite.ToString());

        // geänderte Definitionen speichern
        doc.Save(ConfigSource);
    }

    /// <summary>
    /// ExcludeFromClientQueryString (Standard) 
    /// Eventuelle in destinationUrl angegebene Url-Parameter werden nicht in Page.ClientQueryString eingetragen. So das auch ein einwandfreier Postback möglich ist. Url-Paremter die in der Browser-Adressleiste stehen sind weiterhin in Page.ClientQueryString vorhanden. In Request.QueryString[] sind jedoch alle Url-Parameter vorhanden. 
    /// StoreInContextItems 
    /// Alle Url-Parameter, die aus dem Rewrite und diejenigen die im Browser stehen, werden auch in HttpContext.Current.Items[] abgelegt, vor dem Namen wird ein eventuell angegebener contextItemsPrefix gesetzt. 
    /// Eine Kombination der Parameter ist möglich (mit Komma getrennt).
    /// </summary>
    public enum RewriteUrlParameter {
        ExcludeFromClientQueryString,
        StoreInContextItems
    }
}

Der Aufruf erfolgt so:

UrlRewritingHelper.AddRewrite(Server.MapPath("~/rewrites.config"),
                                "~/default.aspx",
                                "~/default.aspx?contentId=70",
                                UrlRewritingHelper.RewriteUrlParameter.ExcludeFromClientQueryString,
                                true,
                                false);

Die neue Rewrite-Defintion sieht nun wie folgt aus:

<urlrewritingnet rewriteOnlyVirtualUrls="true" compileRegex="true" contextItemsPrefix="QueryString" xmlns="http://www.urlrewriting.net/schemas/config/2006/01">
  <rewrites>
    <add virtualUrl="~/anfahrt/default.aspx" destinationUrl="~/Default.aspx?ContentID=95" ignoreCase="true" rewriteUrlParameter="ExcludeFromClientQueryString" />
    <add virtualUrl="~/kontakt/default.aspx" destinationUrl="~/Default.aspx?ContentID=79" ignoreCase="true" rewriteUrlParameter="ExcludeFromClientQueryString" />
    <add virtualUrl="~/default.aspx" destinationUrl="~/default.aspx?contentId=70" rewriteUrlParameter="ExcludeFromClientQueryString" ignoreCase="True" permanent="False" />
  </rewrites>
</urlrewritingnet>

Randnotiz: Ich habes es via Xml implementiert, da die Add-Methode via .NET 2.0 Configuration.Save() von Thomas und Albert wohl bald selbst implementiert wird.