Pregunta

Me gustaría hacer coincidir " aproximado " coincide en Web.SiteMap

El proveedor de mapa de sitio estático Web.Sitemap funciona bien, excepto por una cosa. ¡ES ESTÁTICO!

Entonces, si tuviera que tener un sitemapnode para cada uno de los 10,000 artículos en mi página, así:

  • site.com/articles/1/article-title
  • site.com/articles/2/another-article-title
  • site.com/articles/3/another-article-again
  • ...
  • site.com/articles/9999/the-last-article

¿Hay algún tipo de mapeo de comodines que pueda hacer con el SiteMap para que coincida con algo en los artículos?

O tal vez en mi página de formularios web, ¿hay alguna manera de configurar manualmente el nodo actual?

He encontrado un " bit " de ayuda en esta página al hacer esto con ASP.Net MVC Framework, pero sigue buscando una buena solución para formularios web.

Creo que lo que voy a tener que hacer es crear un proveedor de SiteMap personalizado

¿Fue útil?

Solución

Esto es en respuesta al comentario anterior. No puedo publicar el código completo, pero así es básicamente cómo funciona mi proveedor.

Suponga que tiene una página article.aspx, y utiliza el parámetro de cadena de consulta " id " para recuperar y mostrar el título y el cuerpo de un artículo. Entonces esto está en Web.sitemap:

<siteMapNode url="/article.aspx" title="(this will be replaced)" param="id" />

Luego, crea esta clase:

public class DynamicSiteMapPath : SiteMapPath
{
  protected override void InitializeItem(SiteMapNodeItem item)
  {
    if (item.ItemType != SiteMapNodeItemType.PathSeparator)
    {
      string url = item.SiteMapNode.Url;
      string param = item.SiteMapNode["param"];

      // get parameter value
      int id = System.Web.HttpContext.Current.Request.QueryString[param];

      // retrieve article from database using id
      <write your own code>

      // override node link
      HyperLink link = new HyperLink();
      link.NavigateUrl = url + "?" + param + "=" + id.ToString();
      link.Text = <the article title from the database>;
      link.ToolTip = <the article title from the database>;
      item.Controls.Add(link);
    }
    else
    {
      // if current node is a separator, initialize as usual
      base.InitializeItem(item);
    }
  }
}

Finalmente, usa este proveedor en su código tal como lo haría con el proveedor estático.

<mycontrols:DynamicSiteMapPath ID="dsmpMain" runat="server" />

Mi clase es más complicada que esto, pero estos son los conceptos básicos. En lugar de utilizar un parámetro de cadena de consulta, puede analizar la URL amigable que está utilizando y utilizarla para recuperar el contenido correcto. Para minimizar las búsquedas de db adicionales con cada solicitud, puede agregar un mecanismo de almacenamiento en caché al proveedor (el título del artículo generalmente no cambiará a menudo).

Espero que esto ayude.

Otros consejos

Creo que esto no es del todo una respuesta a su pregunta, pero tal vez le dé una idea. Una vez escribí una clase DynamicSiteMapPath heredando SiteMapPath. Utilizo un atributo personalizado en cada etiqueta <siteMapNode> en Web.sitemap, como esta:

<siteMapNode url="dynamicpage.aspx" title="blah" params="id" />

Entonces la clase DynamicSiteMapPath obtiene el " id " valor del parámetro, recupera el contenido de la base de datos y anula el nodo del elemento del mapa del sitio actualmente representado con el título y el enlace correctos. Tomará un poco de trabajo, pero cuando se hace correctamente, esta es una forma muy clara de proporcionar soporte dinámico para la página.

Me he encontrado con este problema y, francamente, no he encontrado ninguna solución que me haya hecho feliz ... así que tomo prestadas ideas de aquí y de allá. Mi solución es de varias partes: a) hacer que el SiteMapProvider encuentre la página real que maneja la solicitud y use su nodo yb) use técnicas estándar para actualizar el sitemapnode desde allí.

A) El problema con el que me encontraba constantemente es que si no tuviera la ruta virtual correcta, SiteMap.CurrentNode sería nulo y activaría la función SiteMapResolve. Para resolver esto, subclasifiqué XmlSiteMapProvider y anulé 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 predeterminada no encuentra nada, busque la ruta (si corresponde) e intente encontrar el nodo utilizando la ruta virtual del controlador.

Para referencia aquí es parte de mis archivos Web.Config, Global.asax y SiteMap:

Agregar 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 SiteMap:

        <siteMapNode url="~/Evals/New.aspx" title="New Eval - {type}"  description="" />

B) I subclase System.Web.UI.Page, acertadamente llamado BaseClass, que agrega un método para registrar controladores 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;
    }

Todavía necesito que las URL se asignen correctamente (usarían la URL de la página que recibe la ruta), que es sin información de enrutamiento. Probablemente usaré un Atributo personalizado en el mapa del sitio para decirle al nodo cómo representar la URL.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top