在 ASP.NET 2.0 中为大型网站构建动态站点地图






4.27/5 (18投票s)
2006 年 12 月 21 日
3分钟阅读

362194

7195
在 ASP.NET 中构建大型网站上的动态站点地图的实用方法。
引言
对于具有站点地图文件的静态站点,站点地图和面包屑导航(SiteMapPath)非常有用且易于实现。 对于动态站点,简单的事情似乎变得更加复杂。
当我开始阅读动态站点的站点地图时,我发现一种常见的方法:例如,从数据源为整个网站生成静态站点地图。 定期重新生成。 使用 XmlSiteMapProvider。 缓存。 此 CodeProject 文章中描述了该技术。
这根本不适用于我的网站。 我需要为大量页面提供站点地图,可能达到数十万个。 该站点深度且动态,只有一小部分不可预测的页面被频繁访问。 后端数据库中还有两百种不同的对象类型,这些对象类型与用户界面完全没有耦合。 一次性查询所有内容并非易事。 为整个站点生成准确的站点地图将花费太长时间,需要大量代码,并且肯定会占用太多内存进行缓存。
本文演示了一种更简单、更实用的解决方案。 您可以在 www.foodcandy.com 上看到它的实际效果。
架构
该架构的核心是一个相对简单的动态数据提供程序,SiteMapDataProvider
,它基于 StaticSiteMapProvider
。 该提供程序用作整个应用程序中的默认提供程序,并且可以堆叠站点地图路径中出现的节点。 每个呈现动态内容的文档都将其自身与其父节点的适当层次结构堆叠在一起。
实现
SiteMapDataProvider
非常简单。 它将创建一个根节点,并且可以将节点堆叠在任何现有节点后面,从而创建路径。
public class SiteMapDataProvider : StaticSiteMapProvider
{
private SiteMapNode mRootNode = null;
...
// create the root node
public override void Initialize(string name,
NameValueCollection attributes)
{
base.Initialize(name, attributes);
mRootNode = new SiteMapNode(this, "Home",
"Default.aspx", "Home");
AddNode(mRootNode);
}
public override SiteMapNode FindSiteMapNode(string rawUrl)
{
return base.FindSiteMapNode(rawUrl);
}
// stack a node under the root
public SiteMapNode Stack(string title, string uri)
{
return Stack(title, uri, mRootNode);
}
// stack a node under any other node
public SiteMapNode Stack(string title, string uri,
SiteMapNode parentnode)
{
lock (this)
{
SiteMapNode node = base.FindSiteMapNodeFromKey(uri);
if (node == null)
{
node = new SiteMapNode(this, uri, uri, title);
node.ParentNode =
((parentnode == null) ? mRootNode : parentnode);
AddNode(node);
}
else if (node.Title != title)
{
// support renaming documents
node.Title = title;
}
return node;
}
}
}
我已将上述实现放入 DBlock.SiteMapProvider.dll 程序集中,并在 web.config 中将其引用为默认提供程序。
<?xml version="1.0"?>
<configuration>
<system.web>
<siteMap enabled="true"
defaultProvider="SiteMapDataProvider">
<providers>
<add name="SiteMapDataProvider"
type="DBlock.SiteMapDataProvider, DBlock.SiteMapDataProvider" />
</providers>
</siteMap>
</system.web>
</configuration>
我添加了一个带有 SiteMapPath 的简单母版页和一个默认页面。 这将在 Default.aspx 上产生一个主页(根)站点地图节点。
现在请记住,目标是拥有一个动态站点地图。 我添加了一个按钮,用于重定向到 Default.aspx?id=<guid> 以用于演示目的。 为了相应地显示站点地图,我构建了一个站点地图节点链表,然后将它们堆叠到站点地图中。 以下是 Default.aspx Page_Load
和 SiteMapDataProvider
中的另一个辅助函数来执行堆叠。
string id = Request["id"];
if (!string.IsNullOrEmpty(id))
{
List<KeyValuePair<string, Uri>> nodes =
new List<KeyValuePair<string, Uri>>();
nodes.Add(new KeyValuePair<string,
Uri>("Dynamic Content", new Uri(Request.Url, "Default.aspx?id=")));
nodes.Add(new KeyValuePair<string, Uri>(Request["id"], Request.Url));
((SiteMapDataProvider) SiteMap.Provider).Stack(nodes);
}
public void Stack(List<KeyValuePair<string, Uri>> nodes)
{
SiteMapNode parent = RootNode;
foreach (KeyValuePair<string, Uri> node in nodes)
{
parent = Stack(node.Key, node.Value.PathAndQuery, parent);
}
}
关注点
这对于检索动态内容的页面非常有效。 我的项目通常从数据库或缓存中检索对象,并在每个页面上显示它们。 向每个页面添加两到三行代码会生成实际命中的页面的完整站点地图。
该技术的明显缺点是您必须在每个页面中添加代码以生成站点地图,并且您必须仔细跟踪中间节点的 URL(在上面的示例中为带有空白 ID 的 Default.aspx?id=)以保持一致性。 如果能以某种其他形式描述动态页面之间的关系,以便可以在编译时进行验证,那就太好了。 也许,一种更好(但更复杂)的方法是扩展 XML 提供程序以允许节点中的动态绑定?
您可能还想限制大型站点的站点地图大小,以避免消耗过多内存。 只需在站点地图达到大小限制后清除它即可。
历史
- 2006/12/16:首次发布。