自定义SiteMapProvider实现从SQL Server中读取站点地图数据结构

有一天,我接到了公司指派给我的一个任务,让我为一个Web应用程序编写菜单。菜单的表现形式是一棵无限制深度的树形结构,接到任务后,我的第一选择就是利用SiteMap来实现这个任务。首先,我创建了一个web.sitemap的站点地图数据文件。如示例1-1

<?xml version="1.0" encoding="utf-8" ?>
<siteMap>
  <siteMapNode title="程序菜单" url="" description="">
    <siteMapNode title="系统配置" url="" description="">
      <siteMapNode title="编码维护" url="~/codemanager.aspx" description=""/>
      <siteMapNode title="人员管理" url="~/membermanager.aspx" description="">
      <siteMapNode title="应用配置" url="~/applicationmanager.aspx" description=""/>
    </siteMapNode>
  </siteMapNode>
</siteMap>

然后,利用SiteMapDataSource将这个Web.sitemap文件绑定到了TreeView中。不费吹灰之力,大功告成!我高兴得向公司汇报了我的任务完成情况。然而,在演示程序的时候,总经理提出了一个令我必须重新考虑这个程序的问题。他说,这个菜单需要动态生成,而不是放到或者说不能全部放到静态文件中,而且,在生成菜单的时候要考虑到人员的授权情况,并且,每一个菜单项要能够定义自己的菜单图标。这个突如其来的需求变化,令我必须要重新考虑这个程序的实现。要不人家怎么说没有免费的午餐呢?一直以为捡了个大便宜。到头来,还是该动锹动锹,该抡镐抡镐。

这回,我在数据库中建了一个表。如示例1-2

NodeId                             varchar(10)
NodeName                     varchar(20)
NodeIcon                         varchar(20)
NodeUrl                           varchar(50)
NodeDescrition              varchar(256)
ParentNodeId                 varchar(10)

下一步,是要改变SiteMap的提供程序,使它能够从这个表中读取菜单的信息。于是,我自定义了SiteMapProvider。

public class SqlSiteMapProvider:StaticSiteMapProvider
    {
        Microsoft.Practices.EnterpriseLibrary.Data.Database _Database;
        private bool _Initialized = false;
        /// <summary>
        /// 站点地图根节点
        /// </summary>
        private SiteMapNode _RootNode = null;
        /// <summary>
        /// 清除站点地图中的节点。
        /// </summary>
        protected override void Clear()
        {
            lock (this)
            {
                _RootNode = null;
                base.Clear();
            }
        }
        /// <summary>
        /// 从数据库中检索站点数据并构建站点地图
        /// </summary>
        /// <returns></returns>
        public override SiteMapNode BuildSiteMap()
        {
            //因为SiteMap类是静态的,所以应确保站点地图被构建完成之前,他不要被修改。
            lock (this)
            {
                //如果提供程序没有被初始化,抛出异常。
                if (!IsInitialized)
                {
                    throw new ProviderException("BuildSiteMap called incorrectly.");
                }

                if (_RootNode == null)
                {
                    //清空节点
                    Clear();
                    // 构造根节点
                    string rootNodeId = "";
                    //TODO:具体程序中修改之
                    DbDataReader rootNodeReader = _Database.ExecuteReader(CommandType.Text, "SELECT nodeid, nodeurl, nodename,nodeicon FROM SiteMap WHERE ParentNodeId  IS NULL") as DbDataReader;
                    try
                    {
                        if (rootNodeReader.HasRows)
                        {
                            rootNodeReader.Read();
                            rootNodeId = rootNodeReader.GetString(0);
                            // 为当前的 StaticSiteMapProvider创建一个 SiteMapNode 根节点 .
                            _RootNode = new SiteMapNode(this,
                                                         rootNodeId,
                                                         rootNodeReader.GetString(1),
                                                         rootNodeReader.GetString(2));

                        }
                        else
                        {
                            return null;
                        }
                    }
                    finally
                    {
                        rootNodeReader.Close();
                    }
                   
                    // 构造子节点
                    //TODO:具体程序中修改之
                    System.Data.Common.DbCommand command = _Database.GetSqlStringCommand("SELECT nodeid, nodeurl, nodename,nodeicon FROM SiteMap WHERE ParentNodeId  = @nodeid");
                    _Database.AddInParameter(command,"@nodeid", DbType.String,rootNodeId);

                    DbDataReader childNodesReader = _Database.ExecuteReader(command) as DbDataReader;
                    try
                    {
                        if (childNodesReader.HasRows)
                        {
                            SiteMapNode childNode = null;
                            while (childNodesReader.Read())
                            {
                                childNode = new SiteMapNode(this,
                                                             childNodesReader.GetString(0),
                                                             childNodesReader.GetString(1),
                                                             childNodesReader.GetString(2));

                                //将图标信息添加到节点的自定义属性中。
                                childNode["Icon"] = childNodesReader.GetString(3);

                                //向根节点中添加子节点。
                                AddNode(childNode, _RootNode);
                            }
                        }

                    }
                    finally
                    {
                        childNodesReader.Close();
                    }
                  
                }
                //返回构建后的根节点。
                return _RootNode;
            }

        }
        /// <summary>
        /// 获得已经构建完成的根节点。
        /// </summary>
        /// <returns>SiteMap根节点</returns>
        protected override SiteMapNode GetRootNodeCore()
        {
            return RootNode;
        }
        /// <summary>
        /// 获取当前提供程序是否已经被初始化。
        /// </summary>
        public virtual bool IsInitialized
        {
            get
            {
                return _Initialized;
            }
        }
        /// <summary>
        /// 获取SiteMap根节点
        /// </summary>
        public override SiteMapNode RootNode
        {
            get
            {
                SiteMapNode temp = null;
                temp = BuildSiteMap();
                return temp;
            }
        }
        /// <summary>
        /// 初始化提供程序。
        /// </summary>
        /// <param name="name">提供程序的名称</param>
        /// <param name="config">配置参数</param>
        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
        {
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }
            if (string.IsNullOrEmpty(name))
            {
                name = "AspNetSqlSiteMapProvider";
            }
            if (string.IsNullOrEmpty(config["description"]))
            {
                config.Remove("description");
                config.Add("description", "SiteMapSqlProvider_description");
            }
            base.Initialize(name, config);
            string specifiedConnectionString = config["connectionStringName"];
            if ((specifiedConnectionString == null) || (specifiedConnectionString.Length < 1))
            {
                throw new ProviderException("Connection_name_not_specified");
            }
            _Database = Microsoft.Practices.EnterpriseLibrary.Data.DatabaseFactory.CreateDatabase(specifiedConnectionString);
            _Initialized = true;
        }
    }

再在Web.config中加入这个提供程序的定义

<!--SiteMap提供程序定义-->
    <siteMap defaultProvider="SqlSiteMapProvider">
      <providers>
        <add name="SqlSiteMapProvider"
             type="SqlSiteMapProvider"
             connectionStringName="LocalServer"/>
      </providers>
    </siteMap>

一切OK了现在可以在页面中,一睹芳容了。在页面中,我很顺利的将菜单信息添加到了TreeView中。但是,菜单图标没有显示出来。怎么回事呢?我看了绑定信息,发现节点的自定义属性无法直接绑定到TreeView。于是,我在TreeView的TreeNodeDataBound事件中为节点附上了图标。

protected void MenuTree_TreeNodeDataBound(object sender, TreeNodeEventArgs e)
{
        e.Node.ImageUrl = ((SiteMapNode)e.Node.DataItem)["icon"];
}

再次运行,OK了。

上面的例子中,我没有把权限信息加入,如果需要的话,只需要在创建SiteMapNode节点时,从数据库中检索到每个菜单对应的Roles,然后,将其添加到SiteMapNode中。即可解决权限问题。只是,这个功能需要aspnetdb数据库的支持。

还有,也可以将Web.sitemap文件同SiteMap提供程序结合起来一起使用,这样的话,Web.config文件中定义的提供程序就不需要指定defaultProvider属性了

<!--SiteMap提供程序定义-->
    <siteMap>
      <providers>
        <add name="SqlSiteMapProvider"
             type="SqlSiteMapProvider"
             connectionStringName="LocalServer"/>
      </providers>
    </siteMap>

然后,在web.sitemap文件中需要插入动态数据的地方插入提供程序

<?xml version="1.0" encoding="utf-8" ?>
<siteMap>
  <siteMapNode title="程序菜单" url="" description="">
    <siteMapNode title="系统配置" url="" description="">
            <siteMapNode  provider="SqlSiteMapProvider"/>
    </siteMapNode>
  </siteMapNode>
</siteMap>

而且,可以定义多个提供程序。

 
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值