私はこの問題に直面してきましたが、率直に言って、私を満足させる解決策が見つかりませんでした...そこで、あちこちからアイデアを借りています。私の解決策はマルチパートです。a) SiteMapProvider にリクエストを処理する実際のページを見つけさせ、そのノードを使用させ、b) そこから sitemapnode を更新するための標準的な手法を使用します。
A) 私が何度も遭遇した問題は、正しい仮想パスがないと、SiteMap.CurrentNode が null になり、SiteMapResolve 関数が起動することです。これを解決するために、XmlSiteMapProvider をサブクラス化し、CurrentNode をオーバーライドしました。
namespace WebFormTools
{
class RouteBaseSitemapProvider : XmlSiteMapProvider
{
public override SiteMapNode CurrentNode
{
get
{
var node = base.CurrentNode;
if (node == null)
{
// we don't have a node, see if this is from a route
var page = HttpContext.Current.CurrentHandler as System.Web.UI.Page;
if (page != null && page.RouteData != null)
{
// try and get the Virtual path associated with this route
var handler = page.RouteData.RouteHandler as PageRouteHandler;
if (handler != null) {
// try and find that path instead.
node = FindSiteMapNode(handler.VirtualPath);
}
}
}
return node;
}
}
}
}
基本的に、デフォルトの実装で何も見つからない場合は、ルート (存在する場合) を検索し、ハンドラーの仮想パスを使用してノードを見つけようとします。
参考までに、Web.Config、Global.asax、および SiteMap ファイルの一部を次に示します。
プロバイダーの追加
<siteMap defaultProvider="RouteBaseSitemapProvider">
<providers>
<add name="RouteBaseSitemapProvider" type="WebFormTools.RouteBaseSitemapProvider" siteMapFile="Web.sitemap" />
</providers>
</siteMap>
ルート:
routes.MapPageRoute("EvalRoutes",
"Evals/{type}/New.aspx",
"~/Evals/New.aspx");
そしてサイトマップ:
<siteMapNode url="~/Evals/New.aspx" title="New Eval - {type}" description="" />
B) System.Web.UI.Page をサブクラス化し、適切な名前の BaseClass を作成して、SiteMapResolve イベントのハンドラーを登録するメソッドを追加します。
public System.Web.SiteMapNode Process(System.Web.SiteMapNode currentNode)
{
if (currentNode == null) return currentNode;
var page = HttpContext.Current.CurrentHandler as System.Web.UI.Page;
if (page != null && page.RouteData != null)
{
Dictionary<Regex, string> replacements = new Dictionary<Regex, string>();
// build a list of RegEx to aid in converstion, using RegEx so I can ignore class. Technically I could also
foreach (var key in page.RouteData.Values.Keys)
{
replacements.Add(new Regex(string.Format("\\{{{0}\\}}", key), RegexOptions.IgnoreCase), page.RouteData.Values[key].ToString());
}
// navigate up the nodes
var activeNode = currentNode;
while (activeNode != null)
{
// to the replacements
foreach(var replacement in replacements)
{
activeNode.Title = replacement.Key.Replace(activeNode.Title, replacement.Value);
}
activeNode = activeNode.ParentNode;
}
}
return currentNode;
}
URL を適切にマップする必要があります (ルートを受け取るページの URL を使用します)。これはルーティング情報ではありません。おそらく、サイトマップでカスタム属性を使用して、ノードに URL のレンダリング方法を指示します。