转贴自 http://www.cnblogs.com/zijinguang/articles/1226098.html
SiteMapPath 是ASP.NET 2.0 版包含导航控件中的一种,其它还包括 Menu 控件和TreeView 控件,这些控件使导航菜单的创建、自定义和维护变得很容易导航控件的一种。今天有朋友问我用没有过SiteMapPath 于是从网上找到一个不错的例子转载下,给可能用到此控件的朋友一个帮助。高手现在就可以离开了。
1、创建.sitemap文件,其实就是一个xml文件,包括有着层次结构的<siteMapNode > 元素
2、<siteMapNode>元素的属性:
Url - 链接地址
Title - 显示的标题
Description - 描述(ToolTip)
resourceKey - 本地化用的(要在<siteMap>节点加上这个属性enableLocalization=true)
securityTrimmingEnabled - 是否让sitemap支持安全特性
roles - 哪些角色可以访问当前节点,多角色用逗号隔开(需要将securityTrimmingEnabled设置为true)
siteMapFile - 引用另一个sitemap文件
注:应用权限的时候,Web.config中的SiteMap节点的Provider也要有相对应的配置(securityTrimmingEnabled="true" )
3、可以通过SiteMap和SiteMapNode类访问站点地图数据
4、自定义站点地图提供程序应该写一个继承自StaticSiteMapProvider的类
5、XmlSiteMapProvider要求站点地图节点具有唯一的URL
示例
SiteMap/Web.sitemap(包括一个有siteMapFile属性的节点)
< siteMap xmlns ="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
< siteMapNode url ="~/SiteMap/Test.aspx#1" title ="首页" description ="首页描述" >
< siteMapNode url ="~/SiteMap/Test.aspx#2" title ="频道1" description ="频道1描述" />
< siteMapNode url ="~/SiteMap/Test.aspx#3" title ="频道2" description ="频道2描述" />
< siteMapNode siteMapFile ="WebChild.sitemap" >
</ siteMapNode >
< siteMapNode url ="~/SiteMap/Test.aspx#4" title ="频道4" description ="频道4描述" />
</ siteMapNode >
</ siteMap >
SiteMap/WebChild.sitemap(上面.sitemap文件某个节点的siteMapFile属性所指定的文件)
< siteMap xmlns ="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
< siteMapNode url ="~/SiteMap/Test.aspx#5" title ="频道3" description ="频道3" >
< siteMapNode url ="~/SiteMap/Test.aspx#6" title ="栏目1" description ="栏目1描述" />
< siteMapNode url ="~/SiteMap/Test.aspx#7" title ="栏目2" description ="栏目2描述" />
< siteMapNode url ="~/SiteMap/Test.aspx#8" title ="栏目3" description ="栏目3描述" />
</ siteMapNode >
</ siteMap >
站点地图测试
SiteMap/Test.aspx
Inherits = " SiteMap_Test " Title = " 站点地图测试 " %>
< asp:Content ID ="Content1" ContentPlaceHolderID ="ContentPlaceHolder1" runat ="Server" >
< p >
< asp:TreeView ID ="TreeView1" runat ="server" DataSourceID ="SiteMapDataSource1" >
</ asp:TreeView >
< asp:Menu ID ="Menu1" runat ="server" DataSourceID ="SiteMapDataSource2" Orientation ="Horizontal" >
</ asp:Menu >
<% -- 显示根节点的数据源 -- %>
< asp:SiteMapDataSource ID ="SiteMapDataSource1" runat ="server" SiteMapProvider ="XmlSiteMapProviderTest" />
<% -- 不显示根节点的数据源 -- %>
< asp:SiteMapDataSource ID ="SiteMapDataSource2" runat ="server" SiteMapProvider ="XmlSiteMapProviderTest"
ShowStartingNode ="false" />
</ p >
< p >
编码方式访问节点信息如下 < br />
< asp:Label ID ="lbl" runat ="server" BackColor ="#DDDDDD" />
</ p >
</ asp:Content >
SiteMap/Test.aspx.cs
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
public partial class SiteMap_Test : System.Web.UI.Page
{
protected void Page_Load( object sender, EventArgs e)
{
// 获取当前节点的Title
lbl.Text = " 当前节点标题: " + SiteMap.CurrentNode.Title + " <br /> " ;
// 取得url为“~/Default.aspx”的SiteMapNode
SiteMapNode smn = SiteMap.Provider.FindSiteMapNode( " ~/Default.aspx " );
lbl.Text += " Default.aspx节点的Url: " + smn.Url;
}
}
站点地图测试(从数据库读数据)
SiteMap/FromDatabase.aspx
Inherits = " SiteMap_FromDatabase " Title = " 站点地图测试(从数据库读数据) " %>
< asp:Content ID ="Content1" ContentPlaceHolderID ="ContentPlaceHolder1" runat ="Server" >
< asp:TreeView ID ="TreeView1" runat ="server" DataSourceID ="SiteMapDataSource1" >
</ asp:TreeView >
< asp:SiteMapDataSource ID ="SiteMapDataSource1" runat ="server" SiteMapProvider ="SqlSiteMapProvider" />
</ asp:Content >
自定义站点地图提供程序(SqlServer方式)
SqlSiteMapProvider.cs(“sp_GetSiteMap”为读取站点地图数据的存储过程,详见源码)
using System.Web;
using System.Data.SqlClient;
using System.Collections.Specialized;
using System.Configuration;
using System.Web.Configuration;
using System.Collections.Generic;
using System.Configuration.Provider;
using System.Security.Permissions;
using System.Data.Common;
using System.Data;
/// <summary>
/// SqlSiteMapProvider
/// </summary>
public class SqlSiteMapProvider : StaticSiteMapProvider
{
private string _strCon;
private int _indexID, _indexTitle, _indexUrl, _indexDesc, _indexParent;
// 节点
private SiteMapNode _node;
// 节点字典表
private Dictionary < int , SiteMapNode > _nodes = new Dictionary < int , SiteMapNode > ();
// 用于单例模式
private readonly object _lock = new object ();
/// <summary>
/// 初始化
/// </summary>
/// <param name="name"> name </param>
/// <param name="config"> config </param>
public override void Initialize( string name, NameValueCollection config)
{
// 验证是否有config
if (config == null )
throw new ArgumentNullException( " config不能是null " );
// 没有provider则设置为默认的
if (String.IsNullOrEmpty(name))
name = " SqlSiteMapProvider " ;
// 没有描述就增加一个描述
if ( string .IsNullOrEmpty(config[ " description " ]))
{
config.Remove( " description " );
config.Add( " description " , " SqlSiteMapProvider " );
}
// 调用基类的初始化方法
base .Initialize(name, config);
// 初始化连接字符串
string conStringName = config[ " connectionStringName " ];
if (String.IsNullOrEmpty(conStringName))
throw new ProviderException( " 没找到connectionStringName " );
config.Remove( " connectionStringName " );
if (WebConfigurationManager.ConnectionStrings[conStringName] == null )
throw new ProviderException( " 根据connectionStringName没找到连接字符串 " );
// 获得连接字符串
_strCon = WebConfigurationManager.ConnectionStrings[conStringName].ConnectionString;
if (String.IsNullOrEmpty(_strCon))
throw new ProviderException( " 连接字符串是空的 " );
}
/// <summary>
/// 从持久性存储区加载站点地图信息,并在内存中构建它
/// </summary>
/// <returns></returns>
public override SiteMapNode BuildSiteMap()
{
lock (_lock)
{
// 单例模式的实现
if (_node != null )
return _node;
SqlConnection connection = new SqlConnection(_strCon);
try
{
SqlCommand command = new SqlCommand( " sp_GetSiteMap " , connection);
command.CommandType = CommandType.StoredProcedure;
connection.Open();
SqlDataReader reader = command.ExecuteReader();
// 获得各个字段的索引
_indexID = reader.GetOrdinal( " ID " );
_indexUrl = reader.GetOrdinal( " Url " );
_indexTitle = reader.GetOrdinal( " Title " );
_indexDesc = reader.GetOrdinal( " Description " );
_indexParent = reader.GetOrdinal( " Parent " );
if (reader.Read())
{
// 把第一条记录作为根节点添加
_node = CreateSiteMapNodeFromDataReader(reader);
AddNode(_node, null );
// 构造节点树
while (reader.Read())
{
// 在站点地图中增加一个节点
SiteMapNode node = CreateSiteMapNodeFromDataReader(reader);
AddNode(node, GetParentNodeFromDataReader(reader));
}
}
reader.Close();
}
catch (Exception ex)
{
throw new Exception(ex.ToString());
}
finally
{
connection.Close();
}
// 返回SiteMapNode
return _node;
}
}
/// <summary>
/// 将检索目前由当前提供程序管理的所有节点的根节点
/// </summary>
/// <returns></returns>
protected override SiteMapNode GetRootNodeCore()
{
lock (_lock)
{
return BuildSiteMap();
}
}
/// <summary>
/// 根据DataReader读出来的数据返回SiteMapNode
/// </summary>
/// <param name="reader"> DbDataReader </param>
/// <returns></returns>
private SiteMapNode CreateSiteMapNodeFromDataReader(DbDataReader reader)
{
if (reader.IsDBNull(_indexID))
throw new ProviderException( " 没找到ID " );
int id = reader.GetInt32(_indexID);
if (_nodes.ContainsKey(id))
throw new ProviderException( " 不能有重复ID " );
// 根据字段索引获得相应字段的值
string title = reader.IsDBNull(_indexTitle) ? null : reader.GetString(_indexTitle).Trim();
string url = reader.IsDBNull(_indexUrl) ? null : reader.GetString(_indexUrl).Trim();
string description = reader.IsDBNull(_indexDesc) ? null : reader.GetString(_indexDesc).Trim();
// 新建一个SiteMapNode
SiteMapNode node = new SiteMapNode( this , id.ToString(), url, title, description);
// 把这个SiteMapNode添加进节点字典表里
_nodes.Add(id, node);
// 返回这个SiteMapNode
return node;
}
/// <summary>
/// 得到父节点的SiteMapNode
/// </summary>
/// <param name="reader"></param>
/// <returns></returns>
private SiteMapNode GetParentNodeFromDataReader(DbDataReader reader)
{
if (reader.IsDBNull(_indexParent))
throw new ProviderException( " 父节点不能是空 " );
int pid = reader.GetInt32(_indexParent);
if ( ! _nodes.ContainsKey(pid))
throw new ProviderException( " 有重复节点ID " );
// 返回父节点的SiteMapNode
return _nodes[pid];
}
}
上面两个测试页面所需的web.config中的配置
< appSettings />
< connectionStrings >
< add name ="SqlConnectionString" connectionString ="Data Source=./SQLEXPRESS;AttachDbFilename=|DataDirectory|/Database.mdf;Integrated Security=True;User Instance=True" />
</ connectionStrings >
< system .web >
< siteMap enabled ="true" defaultProvider ="XmlSiteMapProvider" >
< providers >
< add name ="XmlSiteMapProvider" type ="System.Web.XmlSiteMapProvider, System.Web, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" siteMapFile ="~/Web.sitemap" />
< add name ="XmlSiteMapProviderTest" type ="System.Web.XmlSiteMapProvider, System.Web, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" siteMapFile ="~/Sitemap/Web.sitemap" />
< add name ="SqlSiteMapProvider" type ="SqlSiteMapProvider" connectionStringName ="SqlConnectionString" />
</ providers >
</ siteMap >
</ system.web >
</ configuration >
文章作者 webabcd 原文地址 http://www.cnblogs.com/webabcd/archive/2007/02/14/650773.html
以下是微软的代码:
using System;
using System.Web;
using System.Data.SqlClient;
using System.Collections.Specialized;
using System.Configuration;
using System.Web.Configuration;
using System.Collections.Generic;
using System.Configuration.Provider;
using System.Security.Permissions;
using System.Data.Common;
using System.Data;
using System.Web.Caching;
/// <summary>
/// Summary description for SqlSiteMapProvider
/// </summary>
[SqlClientPermission (SecurityAction.Demand, Unrestricted = true )]
public class SqlSiteMapProvider : StaticSiteMapProvider
{
private const string _errmsg1 = " Missing node ID " ;
private const string _errmsg2 = " Duplicate node ID " ;
private const string _errmsg3 = " Missing parent ID " ;
private const string _errmsg4 = " Invalid parent ID " ;
private const string _errmsg5 = " Empty or missing connectionStringName " ;
private const string _errmsg6 = " Missing connection string " ;
private const string _errmsg7 = " Empty connection string " ;
private const string _errmsg8 = " Invalid sqlCacheDependency " ;
private const string _cacheDependencyName = " __SiteMapCacheDependency " ;
private string _connect; // Database connection string
private string _database, _table; // Database info for SQL Server 7/2000 cache dependency
private bool _2005dependency = false ; // Database info for SQL Server 2005 cache dependency
private int _indexID, _indexTitle, _indexUrl, _indexDesc, _indexRoles, _indexParent;
private Dictionary < int , SiteMapNode > _nodes = new Dictionary < int , SiteMapNode > ( 16 );
private readonly object _lock = new object ();
private SiteMapNode _root;
public override void Initialize ( string name, NameValueCollection config)
{
// Verify that config isn't null
if (config == null )
throw new ArgumentNullException( " config " );
// Assign the provider a default name if it doesn't have one
if (String.IsNullOrEmpty(name))
name = " SqlSiteMapProvider " ;
// Add a default "description" attribute to config if the
// attribute doesn锟絫 exist or is empty
if ( string .IsNullOrEmpty(config[ " description " ]))
{
config.Remove( " description " );
config.Add( " description " , " SQL site map provider " );
}
// Call the base class's Initialize method
base .Initialize(name, config);
// Initialize _connect
string connect = config[ " connectionStringName " ];
if (String.IsNullOrEmpty(connect))
throw new ProviderException(_errmsg5);
config.Remove( " connectionStringName " );
if (WebConfigurationManager.ConnectionStrings[connect] == null )
throw new ProviderException(_errmsg6);
_connect = WebConfigurationManager.ConnectionStrings[connect].ConnectionString;
if (String.IsNullOrEmpty(_connect))
throw new ProviderException(_errmsg7);
// Initialize SQL cache dependency info
string dependency = config[ " sqlCacheDependency " ];
if ( ! String.IsNullOrEmpty(dependency))
{
if (String.Equals(dependency, " CommandNotification " , StringComparison.InvariantCultureIgnoreCase))
{
SqlDependency.Start(_connect);
_2005dependency = true ;
}
else
{
// If not "CommandNotification", then extract database and table names
string [] info = dependency.Split( new char [] { ' : ' } );
if (info.Length != 2 )
throw new ProviderException(_errmsg8);
_database = info[ 0 ];
_table = info[ 1 ];
}
config.Remove( " sqlCacheDependency " );
}
// SiteMapProvider processes the securityTrimmingEnabled
// attribute but fails to remove it. Remove it now so we can
// check for unrecognized configuration attributes.
if (config[ " securityTrimmingEnabled " ] != null )
config.Remove( " securityTrimmingEnabled " );
// Throw an exception if unrecognized attributes remain
if (config.Count > 0 )
{
string attr = config.GetKey( 0 );
if ( ! String.IsNullOrEmpty(attr))
throw new ProviderException( " Unrecognized attribute: " + attr);
}
}
public override SiteMapNode BuildSiteMap()
{
lock (_lock)
{
// Return immediately if this method has been called before
if (_root != null )
return _root;
// Query the database for site map nodes
SqlConnection connection = new SqlConnection(_connect);
try
{
SqlCommand command = new SqlCommand( " proc_GetSiteMap " , connection);
command.CommandType = CommandType.StoredProcedure;
// Create a SQL cache dependency if requested
SqlCacheDependency dependency = null ;
if (_2005dependency)
dependency = new SqlCacheDependency(command);
else if ( ! String.IsNullOrEmpty(_database) && ! string .IsNullOrEmpty(_table))
dependency = new SqlCacheDependency(_database, _table);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
_indexID = reader.GetOrdinal( " ID " );
_indexUrl = reader.GetOrdinal( " Url " );
_indexTitle = reader.GetOrdinal( " Title " );
_indexDesc = reader.GetOrdinal( " Description " );
_indexRoles = reader.GetOrdinal( " Roles " );
_indexParent = reader.GetOrdinal( " Parent " );
if (reader.Read())
{
// Create the root SiteMapNode and add it to the site map
_root = CreateSiteMapNodeFromDataReader(reader);
AddNode(_root, null );
// Build a tree of SiteMapNodes underneath the root node
while (reader.Read())
{
// Create another site map node and add it to the site map
SiteMapNode node = CreateSiteMapNodeFromDataReader(reader);
AddNode(node, GetParentNodeFromDataReader(reader));
}
// Use the SQL cache dependency
if (dependency != null )
{
HttpRuntime.Cache.Insert(_cacheDependencyName, new object (), dependency,
Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable,
new CacheItemRemovedCallback(OnSiteMapChanged));
}
}
}
finally
{
connection.Close();
}
// Return the root SiteMapNode
return _root;
}
}
protected override SiteMapNode GetRootNodeCore ()
{
lock (_lock)
{
BuildSiteMap();
return _root;
}
}
// Helper methods
private SiteMapNode CreateSiteMapNodeFromDataReader (DbDataReader reader)
{
// Make sure the node ID is present
if (reader.IsDBNull (_indexID))
throw new ProviderException (_errmsg1);
// Get the node ID from the DataReader
int id = reader.GetInt32 (_indexID);
// Make sure the node ID is unique
if (_nodes.ContainsKey(id))
throw new ProviderException(_errmsg2);
// Get title, URL, description, and roles from the DataReader
string title = reader.IsDBNull (_indexTitle) ? null : reader.GetString (_indexTitle).Trim ();
string url = reader.IsDBNull (_indexUrl) ? null : reader.GetString (_indexUrl).Trim ();
string description = reader.IsDBNull (_indexDesc) ? null : reader.GetString (_indexDesc).Trim ();
string roles = reader.IsDBNull(_indexRoles) ? null : reader.GetString(_indexRoles).Trim();
// If roles were specified, turn the list into a string array
string [] rolelist = null ;
if ( ! String.IsNullOrEmpty(roles))
rolelist = roles.Split( new char [] { ' , ' , ' ; ' } , 512 );
// Create a SiteMapNode
SiteMapNode node = new SiteMapNode( this , id.ToString(), url, title, description, rolelist, null , null , null );
// Record the node in the _nodes dictionary
_nodes.Add(id, node);
// Return the node
return node;
}
private SiteMapNode GetParentNodeFromDataReader(DbDataReader reader)
{
// Make sure the parent ID is present
if (reader.IsDBNull (_indexParent))
throw new ProviderException (_errmsg3);
// Get the parent ID from the DataReader
int pid = reader.GetInt32(_indexParent);
// Make sure the parent ID is valid
if ( ! _nodes.ContainsKey(pid))
throw new ProviderException(_errmsg4);
// Return the parent SiteMapNode
return _nodes[pid];
}
void OnSiteMapChanged( string key, object item, CacheItemRemovedReason reason)
{
lock (_lock)
{
if (key == _cacheDependencyName && reason == CacheItemRemovedReason.DependencyChanged)
{
// Refresh the site map
Clear ();
_nodes.Clear();
_root = null ;
}
}
}
}