10

我想匹配 Web.SiteMap 中的“近似”匹配项

Web.Sitemap 静态站点地图提供程序运行良好,除了一件事。它是静态的!

因此,如果我必须为页面上的 10,000 篇文章中的每一篇都拥有一个站点地图节点,如下所示:

  • 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

我可以使用 SiteMap 进行某种通配符映射以匹配文章下的任何内容吗?

或者也许在我的 Webforms 页面中,有没有办法手动设置当前节点?

使用 ASP.Net MVC 框架执行此操作时,我在此页面上找到了“一点”帮助,但仍在为 Webforms 寻找一个好的解决方案。

我想我要做的是创建一个自定义 SiteMap Provider

4

3 回答 3

7

这是对上述评论的回应。我无法发布完整的代码,但这基本上是我的提供商的工作方式。

假设您有一个页面 article.aspx,它使用查询字符串参数“id”来检索和显示文章标题和正文。然后这是在 Web.sitemap 中:

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

然后,您创建这个类:

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

最后,您可以在代码中使用此提供程序,就像使用静态提供程序一样。

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

我的课比这更复杂,但这些是基础。您可以不使用查询字符串参数,而是分析您正在使用的友好 url,然后使用它来检索正确的内容。为了最大限度地减少每个请求的额外数据库查找,您可以向提供者添加缓存机制(文章标题通常不会经常更改)。

希望这可以帮助。

于 2008-11-20T09:09:44.610 回答
2

我认为这并不完全是您问题的答案,但也许它给了您一个想法。我曾经写过一个继承 SiteMapPath 的 DynamicSiteMapPath 类。<siteMapNode>我在 Web.sitemap 的每个标签中使用自定义属性,如下所示:

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

然后 DynamicSiteMapPath 类获取“id”参数值,从数据库中检索内容,并使用正确的标题和链接覆盖当前呈现的站点地图项节点。这需要一些工作,但如果做得正确,这是提供动态页面支持的一种非常简洁的方式。

于 2008-11-19T12:26:33.497 回答
2

我一直遇到这个问题,坦率地说,没有找到任何让我开心的解决方案......所以我从这里和那里借鉴了一些想法。我的解决方案是多部分的:a)让 SiteMapProvider 找到处理请求的实际页面并使用它的节点,b)使用标准技术从那里更新 sitemapnode。

A) 我一直遇到的问题是,如果我没有正确的虚拟路径,SiteMap.CurrentNode 将为空,并且会触发 SiteMapResolve 函数。为了解决这个问题,我继承了 XmlSiteMapProvider 并覆盖了 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;
            }
        }
    }
}

基本上,如果默认实现没有找到任何东西,请查找路由(如果有)并尝试使用处理程序的虚拟路径查找节点。

这里是我的 Web.Config、Global.asax 和 SiteMap 文件的一部分供参考:

添加提供者

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

路线:

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

和站点地图:

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

B) 我继承了 System.Web.UI.Page,恰当地命名为 BaseClass,它添加​​了一个方法来为 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;
    }

我仍然需要适当地映射 URL(将使用接收路由的页面的 URL),这是没有路由信息的。我可能会在站点地图中使用自定义属性来告诉节点如何呈现 URL。

于 2010-12-17T23:10:53.170 回答