He estado encontrándose con este problema y, francamente, no encontré ninguna solución que me hiciera feliz ... así que tomo prestadas ideas de aquí y de allá. Mi solución es multiparte: a) hacer que SiteMapProvider encuentre la página real que maneja la solicitud y usar su nodo, yb) usar técnicas estándar para actualizar el sitemapnode desde allí.
A) El problema que me encontré es que si no tuviera la ruta virtual correcta, el SiteMap.CurrentNode sería nulo y activaría la función SiteMapResolve. Para resolver esto con subclases y XmlSiteMapProvider hizo caso omiso de 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;
}
}
}
}
Básicamente, si la implementación por defecto no encuentra nada, buscar la ruta (si lo hay) y tratar de encontrar el nodo utilizando la ruta virtual del controlador.
Como referencia aquí es parte de mi Web.Config, Global.asax y SiteMap archivos:
Agregando el proveedor
<siteMap defaultProvider="RouteBaseSitemapProvider">
<providers>
<add name="RouteBaseSitemapProvider" type="WebFormTools.RouteBaseSitemapProvider" siteMapFile="Web.sitemap" />
</providers>
</siteMap>
La ruta:
routes.MapPageRoute("EvalRoutes",
"Evals/{type}/New.aspx",
"~/Evals/New.aspx");
Y el Mapa del Sitio:
<siteMapNode url="~/Evals/New.aspx" title="New Eval - {type}" description="" />
B) Me subclase System.Web.UI.Page, BaseClass bien llamado, lo que añade un método para registrar manejadores para el evento 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;
}
que todavía tiene que tener las direcciones URL de mapa apropiada (el aspirante a utilizar el URL de la página que recibe la ruta), que no contiene información de enrutamiento. Probablemente usaré un Atributo personalizado en el mapa del sitio para decirle al nodo cómo renderizar la URL.
¡Genial! Gracias. Voy a publicar una solución que también se me ocurrió. – Armstrongest
¿Cómo puedo usar esta clase en mi página aspx? cualquier ayuda por favor –