URL-Rewriting mit ASP.NET MVC

Posted by admin | Filed under .NET | Apr 9, 2011 | No Comments »

 

Möchte man ASP.NET MVC einsetzen, um Internetanwendungen zu programmieren, kann man guten Inhalt direkt mit Suchmaschinenoptimierung verknüpfen. Öffentlich zugänglicher Inhalt kann auch Google möglichst gut zugänglich gemacht werden. Die Google-Roboter, die Websites abgrasen und Webseiten in den Index aufnehmen, scheuen vor URL mit Parametern zurück (z.B. www.wetter.de?PLZ=53127) und nehmen statisch erscheinende URL in den Index auf (z.B. www.wetter/53127.html). Das ist ein triftiger Grund, URL statisch aussehen zu lassen. Zusätzlich sehen statische URL freundlicher aus, und können besser gemerkt werden.

Als Erstes definiere ich eine Zuordnung zwischen einem Konfigurationsabschnittshandler und einem Konfigurationsabschnitt. Aus diesem Grund füge ich dem configSections-Knoten in Web.config folgende sectionGroup hinzu:

<configSections>
  <sectionGroup name="myModuleConfig">
    <section name="rewriteModule" type="MyAssembly.RewriteModuleSectionHandler, MyAssembly"/>
  </sectionGroup>
</configSections>

Dementsprechend muss ich dann im configuration-Knoten den Konfigurationsabschnitt definieren:

<myModuleConfig>
  <rewriteModule>
    <rewriteOn>true</rewriteOn>
    <rewriteRules>
      <rule source="Keyword/(.+).aspx" destination="Keyword?keyword=$1"/>
    </rewriteRules>
  </rewriteModule>
 </myModuleConfig>

In diesem Abschnitt definiere ich, ob das URL-Rewriting stattfinden soll und ich definiere Rewrite-Rules, so wie man das unter PHP in einer .htaccess-Datei tun würde.

Nun muss ich den Konfigurationsabschnittshandler RewriteModuleSectionHandler denn auch in Code gießen:

public class RewriteModuleSectionHandler : IConfigurationSectionHandler
{

    private XmlNode _XmlSection;
    private string _RewriteBase;
    private bool _RewriteOn;

    public XmlNode XmlSection
    {
        get { return _XmlSection; }
    }

    public string RewriteBase
    {
        get { return _RewriteBase; }
    }

    public bool RewriteOn
    {
        get { return _RewriteOn; }
    }
    public object Create(object parent, object configContext, System.Xml.XmlNode section)
    {
        _RewriteBase = HttpContext.Current.Request.ApplicationPath + "/";

        try
        {
            _XmlSection = section;
            _RewriteOn = Convert.ToBoolean(section.SelectSingleNode("rewriteOn").InnerText);
        }
        catch (Exception ex)
        {
            throw (new Exception("Error while processing RewriteModule configuration section.", ex));
        }
        return this;
    }
}

Im Wesentlichen nimmt mein Handler bei Erzeugung seinen XML-Knoten in Empfang und dient mir dazu, den XML-Zugriff zu kapseln.

Zusätzlich definiere ich in der Web.config ein HTTP-Modul:

<system.web>
  <httpModules>
    <add name="RewriteModule" type="MyAssembly.RewriteModule, MyAssembly"/>
  </httpModules>
</system.web>

In C#-Code gegossen:

class RewriteModule : IHttpModule
{

    public void Dispose() { }

    public void Init(HttpApplication context)
    {
        context.BeginRequest += new EventHandler(RewriteModule_BeginRequest);
    }

    void RewriteModule_BeginRequest(object sender, EventArgs e)
    {
        RewriteModuleSectionHandler cfg = (RewriteModuleSectionHandler)ConfigurationManager.GetSection("myModuleConfig/rewriteModule");

        if (!cfg.RewriteOn) return;

        string path = HttpContext.Current.Request.Path;

        if (path.Length == 0) return;

        XmlNode rules = cfg.XmlSection.SelectSingleNode("rewriteRules");
        foreach (XmlNode xml in rules.SelectNodes("rule"))
        {
            try
            {
                string attrsource = "/" + xml.Attributes["source"].InnerText;

                Regex re = new Regex(attrsource, RegexOptions.IgnoreCase);

                Match match = re.Match(path);
                if (match.Success)
                {
                    path = re.Replace(path, xml.Attributes["destination"].InnerText);
                    // new path to rewrite to
                    string rew = cfg.RewriteBase + path;

                    // rewrite
                    HttpContext.Current.RewritePath(rew);

                    return;
                }
            }
            catch (Exception ex)
            {
                throw (new Exception("Incorrect rule.", ex));
            }
        }
        return;
    }

}

in der Init-Methode, die mir das IHttpModule-Interface vorschreibt, bekomme ich eine Referenz auf die Anwendung übergeben. Ich füge dem Anwendungsevent BeginRequest als EventHandler einen Delegaten hinzu, der mir schließlich meine URL-Rewritefunktion aufruft:
void RewriteModule_BeginRequest(object sender, EventArgs e)

Nachdem ich meinen RewriteModuleSectionHandler instanziiert habe (über RewriteModuleSectionHandler cfg = (RewriteModuleSectionHandler)ConfigurationManager.GetSection("myModuleConfig/rewriteModule") findet die Instanziierung nur einmal statt), gehe ich alle Rewrite-Regeln durch und prüfe mit Regex und Match, ob der reguläre Ausdruck der Anfrage-URL mit dem der Regel übereinstimmt. Mit Regex.Replace(…) wird die URL endlich umgeschrieben.


 

 

Leave a Reply