ASP.NET 2.0 中的站点导航提供程序向应用程序中的页公开导航信息,使您可以独立于页的实际物理布局定义站点的结构。默认站点导航提供程序基于XML,但通过为站点地图编写自定义提供程序,也可以从任意后端公开此信息。 关键 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属性的节点)
<? xml version="1.0" encoding="utf-8" ?> < 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属性所指定的文件)
<? xml version="1.0" encoding="utf-8" ?> < 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
<% @ Page Language = " C# " MasterPageFile = " ~/Site.master " AutoEventWireup = " true " CodeFile = " Test.aspx.cs " 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; 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
<% @ Page Language = " C# " MasterPageFile = " ~/Site.master " AutoEventWireup = " true " CodeFile = " FromDatabase.aspx.cs " 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; 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 > (); // for 线程安全 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中的配置
< configuration > < 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 >