2008-11-15 28 views
9

me gustaría coincidir "aproximada" coincide en web.sitemapweb.sitemap con Dynamic URL (URL Enrutamiento)

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

lo tanto, si yo tendría 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/ artículos/2/otro título-artículo-
  • site.com/articles/3/another-article-again
  • ...
  • site.com/articles/9999/the-last-article

¿Hay algún tipo de asignación de comodín que pueda hacer con el Mapa del sitio para que coincida con Cualquier cosa en virtud de los Artículos?

O tal vez en mi página de Webforms, ¿hay alguna manera de establecer manualmente el nodo actual?

He encontrado un "bit" de ayuda en this page al hacer esto con ASP.Net MVC Framework, pero aún estoy buscando una buena solución para Webforms.

creo que lo que voy a tener que hacer es crear un proveedor de SiteMap encargo

Respuesta

7

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

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

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

continuación, se 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); 
    } 
    } 
} 

Por último, se utiliza este proveedor en su código al igual que lo haría con el proveedor de estática.

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

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

Espero que esto ayude.

+0

¡Genial! Gracias. Voy a publicar una solución que también se me ocurrió. – Armstrongest

+0

¿Cómo puedo usar esta clase en mi página aspx? cualquier ayuda por favor –

2

Esto no es del todo una respuesta a su pregunta, creo, pero tal vez le da una idea. Una vez escribí una clase DynamicSiteMapPath heredando SiteMapPath. Yo uso un atributo personalizado en cada etiqueta en <siteMapNode> Web.sitemap, así:

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

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

+0

Me gustaría saber más información sobre esto. Suena interesante. – Armstrongest

2

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.

Cuestiones relacionadas