URL Rewrite und der SiteMap-Provider (Request.PathInfo)

Heute wollte ich einer meiner Seiten so umstellen, dass URL-Rewrite verwendet wird. Das ging auch recht schnell (entsprechende Links gesetzt und über Request.PathInfo die Parameter ausgelesen), allerdings stellte sich beim Testen dann heraus, dass ich ein Problem mit dem Menü hatte. Dieses konnte nun nicht mehr die aktuelle Seite markieren… Das Menü wird über eine Sitemap erstellt.

Verkürzt sieht der Code für das Menü so aus:

1
2
<asp:SiteMapDataSource ID="MenuSource" runat="server" SiteMapProvider="menu" />
<asp:Menu ID="mnu" runat="server" DataSourceID="MenuSource">

In meiner Sitemap sind die entsprechenden URLs eingetragen. Z.B.

1
2
3
<siteMapNode title="Startseite" url="~/default.aspx" />
<siteMapNode title="Projekte" url="~/projects.aspx"/>
<siteMapNode title="Eigene Projekte" url="~/projects.aspx/own"/>

Wird die Seite /projects.aspx aufgerufen, so wird der Eintrag “Projekte” entsprechend gekennzeichnet (mittels CSS-Class “AspNet-Menu-Selected”). Das hat auch noch mit /projects.aspx?test=1 wunderbar funktioniert. Wird dagegen die Seite /projects.aspx/test aufgerufen, wird der entsprechende Eintrag nicht mehr gefunden, da mit Request.RawURL verglichen wird - und da steht /projects/test drin.

Es ist also nur verständlich, dass der Provider den Eintrag nicht findet und dementsprechend kein Menüeintrag als aktiv gekennzeichnet werden kann. Erschwerend kommt hinzu, dass durchaus auch mal ein Treffer dabei sein kann (wie in diesem Beispiel beim Aufruf von /projects.aspx/own).

Da hilft nur selbst den richtigen Eintrag suchen. Das ist natürlich nur nötig, wenn Request.PathInfo gefüllt ist.

1
2
3
4
5
6
7
8
9
10
11
12
protected override void OnInit(EventArgs e) {
base.OnInit(e);
if (MenuSource.Provider.CurrentNode == null && !string.IsNullOrEmpty(Request.PathInfo)) {
MenuSource.Provider.SiteMapResolve += new SiteMapResolveEventHandler(SiteMap_SiteMapResolve);
}
}
private SiteMapNode SiteMap_SiteMapResolve(object sender, SiteMapResolveEventArgs e) {
SiteMapProvider provider = sender as SiteMapProvider;
if (provider == null) return null;
return provider.FindSiteMapNode(e.Context.Request.AppRelativeCurrentExecutionFilePath);
}

Sobald MenuSource.Provider.CurrentNode == null ist und in Request.PathInfo etwas steht, wird auf das Ereignis SiteMapResolve des Providers reagiert. Dort wird nach einem Eintrag im aktuellen SiteMapProvider gesucht, der nur dem Pfad (ohne PathInfo-Angaben) entspricht.

Wenn man das Menü innerhalb eines Controls hat, muss der Code auch nur 1x angegeben werden.