Domanda

Vorrei abbinare " approssimativo " partite in Web.SiteMap

Il provider di sitemap statico Web.Sitemap funziona bene, tranne una cosa. È STATICO!

Quindi, se dovessi avere un sitemapnode per ciascuno dei 10.000 articoli sulla mia pagina in questo modo:

  • 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

Esiste una sorta di mappatura di caratteri jolly che posso fare con SiteMap per abbinare qualsiasi cosa sotto Articoli?

O forse nella mia pagina Webforms, c'è un modo per impostare manualmente il nodo corrente?

Ho trovato un " bit " di aiuto su questa pagina quando si esegue questa operazione con ASP.Net MVC Framework, ma ancora alla ricerca di una buona soluzione per i moduli Web.

Penso che quello che dovrò fare è creare un provider SiteMap personalizzato

È stato utile?

Soluzione

Questo è in risposta al commento sopra. Non riesco a pubblicare il codice completo, ma in pratica funziona così il mio provider.

Supponi di avere una pagina article.aspx e che usi il parametro della stringa di query " id " per recuperare e visualizzare il titolo e il corpo di un articolo. Quindi questo è in Web.sitemap:

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

Quindi, crei questa classe:

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);
    }
  }
}

Infine, usi questo provider nel tuo codice proprio come faresti con il provider statico.

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

La mia classe è più complicata di così, ma queste sono le basi. Invece di utilizzare un parametro querystring, potresti semplicemente analizzare l'URL amichevole che stai utilizzando e utilizzarlo invece per recuperare il contenuto corretto. Per ridurre al minimo le ricerche di database aggiuntive con ogni richiesta, puoi aggiungere un meccanismo di memorizzazione nella cache al provider (il titolo dell'articolo di solito non cambia spesso).

Spero che questo aiuti.

Altri suggerimenti

Penso che questa non sia una risposta alla tua domanda, ma forse ti dà un'idea. Una volta ho scritto una classe DynamicSiteMapPath ereditando SiteMapPath. Uso un attributo personalizzato in ogni <siteMapNode> tag in Web.sitemap, in questo modo:

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

Quindi la classe DynamicSiteMapPath ottiene il " id " valore del parametro, recupera il contenuto dal database e sovrascrive il nodo dell'elemento Sitemap attualmente visualizzato con il titolo e il collegamento corretti. Ci vorrà un po 'di lavoro, ma se fatto correttamente questo è un modo molto accurato di fornire supporto dinamico alla pagina.

Mi sono imbattuto in questo problema e, francamente, non ho trovato soluzioni che mi rendessero felice ... quindi prendo in prestito idee da qui e là. La mia soluzione è multi-parte: a) fai in modo che SiteMapProvider trovi la pagina effettiva che gestisce la richiesta e usa il suo nodo eb) usa tecniche standard per aggiornare il sitemapnode da lì.

A) Il problema che ho riscontrato è che se non avessi il percorso virtuale corretto, SiteMap.CurrentNode sarebbe nullo e la funzione SiteMapResolve non funzionerebbe. Per risolvere il problema, ho eseguito la sottoclasse di XmlSiteMapProvider e sovrascritto 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;
            }
        }
    }
}

Fondamentalmente se l'implementazione predefinita non trova nulla, cerca la route (se presente) e prova a trovare il nodo usando il percorso virtuale del gestore.

Per riferimento qui è parte dei miei file Web.Config, Global.asax e SiteMap:

Aggiunta del provider

    <siteMap defaultProvider="RouteBaseSitemapProvider">
  <providers>
    <add name="RouteBaseSitemapProvider" type="WebFormTools.RouteBaseSitemapProvider" siteMapFile="Web.sitemap" />
  </providers>
</siteMap>

Il percorso:

            routes.MapPageRoute("EvalRoutes",
            "Evals/{type}/New.aspx",
            "~/Evals/New.aspx");

E la SiteMap:

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

B) Sottoclasse System.Web.UI.Page, opportunamente chiamato BaseClass, che aggiunge un metodo per registrare i gestori per l'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;
    }

Devo ancora avere la mappa degli URL in modo appropriato (userebbe l'URL della pagina che riceve il percorso), che è senza informazioni di routing. Probabilmente userò un attributo personalizzato nella mappa del sito per dire al nodo come eseguire il rendering dell'URL.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top