2008-11-15 11 views
9

würde Ich mag „ungefähr“ in Web.sitemap passt entsprechenMit Web.sitemap mit Dynamische URLs (URL Routing)

Die Web.sitemap statische Sitemap Anbieter funktioniert gut, außer für eine Sache. ES IST STATISCH!

Also, wenn ich habe eine SiteMapNode für jede der 10.000 Artikel wie so auf meiner Seite haben:

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

Gibt es eine Art Wildcard-Mapping, das ich mit der SiteMap machen kann, um irgendetwas unter Artikel zu finden?

Oder gibt es vielleicht in meiner Webforms-Seite eine Möglichkeit, den aktuellen Knoten manuell festzulegen?

Ich habe ein "Bit" der Hilfe auf this page gefunden, wenn dies mit dem ASP.Net MVC Framework, aber immer noch auf der Suche nach einer guten Lösung für Webforms.

Ich denke, was ich tun zu müssen, ist eine benutzerdefinierte SiteMap Provider erstellen

Antwort

7

Dies ist als Reaktion auf den obigen Kommentar. Ich kann den vollständigen Code nicht posten, aber im Prinzip funktioniert mein Provider so.

Angenommen, Sie haben eine Seite article.aspx und verwenden den Abfragezeichenfolgenparameter "id", um den Titel und den Text eines Artikels abzurufen und anzuzeigen. Dann ist dies in Web.sitemap:

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

Dann erstellen Sie diese Klasse:

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

Schließlich verwenden Sie diesen Anbieter in Ihrem Code wie Sie den statischen Anbieter verwenden würde.

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

Meine Klasse ist komplizierter als das, aber das sind die Grundlagen. Anstatt einen Querystring-Parameter zu verwenden, können Sie einfach die freundliche URL analysieren, die Sie verwenden, und stattdessen den richtigen Inhalt abrufen. Um die zusätzlichen Db-Lookups bei jeder Anfrage zu minimieren, können Sie dem Provider einen Caching-Mechanismus hinzufügen (der Artikeltitel ändert sich normalerweise nicht oft).

Hoffe, das hilft.

+0

Cool! Vielen Dank. Ich werde eine Lösung posten, die ich mir ausgedacht habe. – Armstrongest

+0

Wie kann ich diese Klasse in meiner Aspx-Seite verwenden? jede Hilfe bitte –

2

Diese nicht ganz eine Antwort auf Ihre Frage ist, glaube ich, aber vielleicht gibt es Ihnen eine Idee. Ich habe einmal eine DynamicSiteMapPath-Klasse geschrieben, die SiteMapPath erbt. Ich verwende ein benutzerdefiniertes Attribut in jedem <siteMapNode> Tag in Web.sitemap, wie folgt aus:

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

Dann wird die DynamicSiteMapPath Klasse bekommt die „id“ Parameterwert, ruft den Inhalt aus der Datenbank und überschreibt die aktuell gerenderte Sitemap Artikel Knoten mit dem richtigen Titel und Link. Es wird ein wenig Arbeit brauchen, aber wenn es richtig gemacht wird, ist dies eine sehr gute Möglichkeit, um dynamische Seiten zu unterstützen.

+0

Ich würde gerne mehr Informationen dazu wissen. Das klingt interessant. – Armstrongest

2

Ich bin auf dieses Problem gestoßen und, offen gesagt, keine Lösungen zu finden, die mich glücklich gemacht haben ... so borge ich Ideen von hier und dort aus. Meine Lösung ist mehrteilig: a) Lassen Sie den SiteMapProvider die Seite finden, die die Anfrage bearbeitet, und verwenden Sie den Knoten und b) verwenden Sie Standardtechniken, um den sitemapnode von dort zu aktualisieren.

A) Das Problem, mit dem ich fortgefahren bin, ist, dass, wenn ich nicht den richtigen virtuellen Pfad hätte, der SiteMap.CurrentNode null wäre und die SiteMapResolve-Funktion auslöst. Um dies zu lösen ich subclassed XmlSiteMapProvider und overrode 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; 
      } 
     } 
    } 
} 

Grundsätzlich, wenn die Standardimplementierung der nichts finden, um die Strecke sehen (falls vorhanden) und versuchen, den Knoten zu finden mit Hilfe der virtuellen Pfad absetzen.

Als Referenz hier ist ein Teil meiner Web.Config, Global.asax und Sitemaps:

den Anbieter

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

Die Route hinzufügen:

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

Und die SiteMap:

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

B) I Unterklasse System.Web.UI.Page, treffend benannt Baseclass, das ein Verfahren fügt Handler für das SiteMapResolve Ereignis registrieren:

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

Ich muss noch die URLs entsprechend abbilden haben (das würde verwenden die URL der Seite, die die Route empfängt), die keine Routinginformationen enthält. Ich werde wahrscheinlich ein benutzerdefiniertes Attribut in der Sitemap verwenden, um dem Knoten mitzuteilen, wie die URL gerendert werden soll.