我一直遇到这个问题,坦率地说,没有找到任何让我开心的解决方案......所以我从这里和那里借鉴了一些想法。我的解决方案是多部分的:a)让 SiteMapProvider 找到处理请求的实际页面并使用它的节点,b)使用标准技术从那里更新 sitemapnode。
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。