2008-11-15 15 views
9

je voudrais correspondre « approximative » correspond à Web.sitemapUtilisation de Web.sitemap avec Dynamic URLS (URL de routage)

Le fournisseur Web.sitemap statique plan du site fonctionne bien, sauf pour une chose. C'EST STATIQUE!

Donc, si je dois avoir un SiteMapNode pour chacun des 10.000 articles sur ma page comme ceci:

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

Existe-t-il une sorte de mappage générique que je peux faire avec SiteMap pour faire correspondre Anything under Articles?

Ou peut-être dans ma page Webforms, est-il un moyen de définir manuellement le nœud actuel?

J'ai trouvé un "peu" d'aide sur this page en faisant cela avec ASP.Net MVC Framework, mais toujours à la recherche d'une bonne solution pour Webforms.

Je pense que je vais devoir faire est de créer un SiteMap personnalisé fournisseur

Répondre

7

Ceci est en réponse au commentaire ci-dessus. Je ne peux pas publier le code complet, mais c'est essentiellement le fonctionnement de mon fournisseur. Supposons que vous ayez une page article.aspx, et qu'il utilise le paramètre de chaîne de requête "id" pour extraire et afficher le titre et le corps d'un article. Alors ceci est en Web.sitemap:

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

Ensuite, vous créez cette 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); 
    } 
    } 
} 

Enfin, vous utilisez ce fournisseur dans votre code comme vous utilisez le fournisseur statique.

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

Ma classe est plus compliquée que cela, mais ce sont les bases. Au lieu d'utiliser un paramètre querystring, vous pouvez simplement analyser l'URL conviviale que vous utilisez et l'utiliser à la place pour récupérer le contenu correct. Pour minimiser les recherches db supplémentaires avec chaque requête, vous pouvez ajouter un mécanisme de mise en cache au fournisseur (le titre de l'article ne changera généralement pas souvent).

Espérons que cela aide.

+0

Cool! Merci. Je vais poster une solution que j'ai trouvée aussi. – Armstrongest

+0

Comment puis-je utiliser cette classe dans ma page aspx? toute aide s'il vous plaît –

2

Ce n'est pas tout à fait une réponse à votre question, je pense, mais peut-être cela vous donne une idée. J'ai déjà écrit une classe DynamicSiteMapPath héritant SiteMapPath. J'utilise un attribut personnalisé dans chaque balise <siteMapNode> dans Web.sitemap, comme ceci:

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

Puis la classe DynamicSiteMapPath obtient la valeur du paramètre « id », extrait le contenu de la base de données, et remplace le moment rendu élément plan du site nœud avec le titre et le lien corrects. Ça va prendre un peu de travail, mais quand c'est fait correctement, c'est un moyen très utile de fournir un support de page dynamique.

+0

J'aimerais connaître plus d'informations à ce sujet. Ça semble intéressant. – Armstrongest

2

J'ai été confronté à ce problème et, franchement, je n'ai trouvé aucune solution qui m'a fait plaisir ... alors j'emprunte des idées ici et là. Ma solution est en plusieurs parties: a) SiteMapProvider trouve la page réelle traitant la demande et utilise son nœud et b) utilise des techniques standard pour mettre à jour le sitemapnode à partir de là.

A) Le problème que j'ai rencontré est que si je n'avais pas le chemin virtuel correct, SiteMap.CurrentNode serait null et déclencherait la fonction SiteMapResolve. Pour résoudre cela, je XmlSiteMapProvider et l'emportaient sur sous-classé 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; 
      } 
     } 
    } 
} 

En gros, si l'implémentation par défaut ne trouve rien, regardez la route (le cas échéant) et essayer de trouver le nœud en utilisant le chemin virtuel du gestionnaire.

Pour référence est ici une partie de mon web.config, les fichiers Global.asax et SiteMap:

Ajout du fournisseur

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

L'itinéraire:

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

Et le SiteMap:

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

B) sous-classe I System.Web.UI.Page, porte bien son nom BaseClass, qui ajoute une méthode pour enregistrer les gestionnaires pour l'événement 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; 
    } 

je dois encore avoir les URL carte appropriée (l'utiliseraient la URL de la page recevant l'itinéraire), qui est sans informations de routage. J'utiliserai probablement un attribut personnalisé dans le sitemap pour indiquer au noeud comment rendre l'URL.