SiteMapDataSource や SiteMapPath コントロールでSiteMapProvider を使用するとツリーやパンくずリストを作成することができます。ASP.NET で標準で用意されている実装は XmlSiteMapProvider です。 今回は カスタムSiteMapProvider を作成してみます。

直接SiteMapProvider を継承して実装するのではなく、 ASP.NET で提供されるStaticSiteMapProvider を継承します。 StaticSiteMapProvider はXmlSIteMapProvider の親クラスでもあります。

下記リンクでStaticSiteMapProvider の解説が確認できます。カスタムサイトマッププロバイダの実装例も掲載されているので、そちらを確認されてもよいと思います。

StaticSiteMapProvider クラス
http://msdn.microsoft.com/ja-jp/library/system.web.staticsitemapprovider.aspx

動作確認環境

  • 動作環境:IIS 6.0およびVisual Studio 2008 組み込みサーバ on Windows 2003
  • 開発環境:Visual Studio 2008 Professional
  • .NET 3.5

1. カスタムサイトマッププロバイダの実装

カスタムサイトマッププロバイダを実装するには、SiteMapProvider を実装します。動的にURLが変更したりするのでなければ、SiteMapProvider を直接実装するよりも、StaticSiteMapProvider を実装する方が簡単です。今回は、完全なコードではありませんが、StaticSiteMapProvider を継承して実装するサンプルを掲載します。

StaticSiteMapProvider は基本的にはメソッドBuidSiteMap のみを実装し、AddNode,Clear,RemoveNodeを使用してサイトマップノードのツリーを構築し、サイトマップのルートノードのSiteMapNode を返せばOKです。 ただし、URL書き換えなどを行っていて、作成したSiteMapNode でノードをうまく発見できない場合は、FindSiteMapNode をオーバーライドして、カスタムでSiteMapNode を発見するコードを記述します。

詳細は記載しませんが、GetChildNodes メソッドで子SiteMapNode を作成しています。FindSiteMapNode をオーバーライドするサンプルとして、特定のURLの場合に、URLを書き換えてノードを再検索しています。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Text.RegularExpressions;

namespace Sample.SiteMap
{
    class CustomSiteMapProvider : StaticSiteMapProvider
    {
        private SiteMapNode _root = null;
        public override SiteMapNode BuildSiteMap()
        {
            if (_root == null)
            {
                lock (this)
                {
                    // ノードクリア
                    Clear();
                  // ルートノードの構築
                    _root = new SiteMapNode(this, "Home", "~/Default.aspx", "ホーム", "ホームです");
                    List<SiteMapNode> childnodes = GetChildNodes();
                    foreach (SiteMapNode node in childnodes)
                    {
                        AddNode(node, _root);
                    }
                }
            }
            return _root;
        }
        // 現在のサイトのルートノードを返す
        protected override SiteMapNode GetRootNodeCore()
        {
            return _root;
        }
        // 通常のFindSiteMapNodeで発見できない動的URLに対応する
        public override SiteMapNode FindSiteMapNode(HttpContext context)
        {
            SiteMapNode node = base.FindSiteMapNode(context);
            if (node == null)
            {
                Regex regex = new Regex(@".+/CatID/(?<cid>\d+)/.+\.aspx");
                Match m = regex.Match(context.Request.RawUrl);
                if (m.Success)
                {
                    string path = regex.Replace(context.Request.RawUrl, "~/BrowseArticles/CatID/${cid}.aspx");
                    node = FindSiteMapNode(path);
                }
            }
            if (node == null)
            {
                node = _root;
            }

            return node;
        }
    }
}

2. おわりに

簡単ですが、説明は以上です。上記の実装では、ページが動的に追加された場合に対応できないなど、複雑なサイトマップ構成の場合は考慮しなければならない点が出てくると思いますが、単純なSiteMapProvider は以外に簡単に作成できると思います。

間違い、指摘点などがありましたらご指摘ください。