
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];

}

}