Я столкнулся с этой проблемой и, честно говоря, не нашел решений, которые бы делали меня счастливым ... поэтому я заимствую идеи здесь и там. Мое решение состоит из нескольких частей: а) пусть SiteMapProvider находит фактическую страницу, обрабатывающую запрос, и использует ее узел, и б) использует стандартные методы для обновления оттуда sitemap.
A) Проблема, с которой я продолжал сталкиваться, заключается в том, что, если бы у меня не было правильного виртуального пути, SiteMap.CurrentNode был бы нулевым, а функция 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.