10

Web.SiteMap で「おおよその」一致を一致させたい

Web.Sitemap 静的サイトマップ プロバイダーは、1 つのことを除いてうまく機能します。それは静的です!

したがって、ページ上の 10,000 件の記事ごとに sitemapnode が必要な場合は、次のようになります。

  • 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 フレームワークでこれを行うときに、このページで「少し」のヘルプを見つけましたが、それでも Web フォームの適切なソリューションを探しています。

私がしなければならないことは、カスタム SiteMap プロバイダーを作成することだと思います

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

私はこの問題に直面してきましたが、率直に言って、私を満足させる解決策が見つかりませんでした...そこで、あちこちからアイデアを借りています。私の解決策はマルチパートです。a) SiteMapProvider にリクエストを処理する実際のページを見つけさせ、そのノードを使用させ、b) そこから sitemapnode を更新するための標準的な手法を使用します。

A) 私が何度も遭遇した問題は、正しい仮想パスがないと、SiteMap.CurrentNode が null になり、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 に答える
2

これはあなたの質問に対する完全な答えではないと思いますが、アイデアが得られるかもしれません。以前、SiteMapPath を継承する DynamicSiteMapPath クラスを作成しました。<siteMapNode>次のように、Web.sitemap の各タグでカスタム属性を使用します。

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

次に、DynamicSiteMapPath クラスは「id」パラメーター値を取得し、データベースからコンテンツを取得して、現在レンダリングされているサイトマップ アイテム ノードを正しいタイトルとリンクでオーバーライドします。少し手間がかかりますが、正しく実行すると、動的なページ サポートを提供する非常に優れた方法になります。

于 2008-11-19T12:26:33.497 に答える