摘要:ASP.NET 2.0 站点导航系统构建于一个功能强大、灵活的体系结构之上,设计这样的体系结构是为了使其具有可扩展性。本文探究站点提供程序的体系结构并提供一个示例提供程序,该提供程序将文件系统公开为站点导航的数据源,从而替代了标准的 Web.sitemap XML 文件。
简介
大多数 web 站点采用可视化导航的某种形式来帮助用户轻松地浏览站点,以及查找他们所需的信息和 Web 页。尽管不同站点之间的感观效果千差万别,但是通常会使用相同的基本元素 — 以导航栏或菜单列表的形式使用户定位到 web 站点的特定位置。
ASP.NET 1.x 提供的针对站点导航现成的支持很少,导致很多开发人员和 web 设计人员不是构建自己的导航系统,就是购买第三方控件以满足他们的需求。而 ASP.NET 2.0 对此作出了改进,它引入一个使用可插接式框架的导航系统,该框架能够公开站点层次结构和插入这个新模型的控件,因此易于构造一个高质量的菜单和导航系统。
本文描述 ASP.NET 2.0 导航系统的工作原理并展示如何对其进行扩展 — 不仅仅是使用简单的 XML 文件(Visual Studio 2005 中使用的默认机制)。
理解 ASP.NET 2.0 中的导航系统
ASP.NET 2.0 导航系统的一个目标是创建一个可以吸引开发人员和 web 站点设计人员的优秀的导航模型,除此之外,它还有一个目标是创建一个提供可扩展性功能的体系结构,该功能能够灵活地满足广泛的需求。该系统基于一个提供程序模型,该模型的使用贯穿于整个 ASP.NET 2.0 框架,由 ASP.NET 2.0 框架提供一个标准的机制用于插入不同的数据源。
ASP.NET 2.0 导航框架可以分解为几个部分:
• 开发人员在实际 web 页面上使用的web 导航控件(Menu、TreeView 和 SiteMapPath)。这些控件可以通过自定义改变感观效果。
• TreeView 和菜单导航控件绑定的 SiteMapDataSource 控件,在 Web 导航控件和导航信息的底层提供程序之间提供一个抽象层。
• 站点地图提供程序是可插接式提供程序,它用于公开描述 web 站点布局的实际信息。ASP.NET 提供了一个提供程序 XmlSiteMapProvider,它使用一个具有特定结构的 XML 文件作为其数据存储。
这种分层的体系结构在底层的站点层次结构和 web 站点上的控件之间制造了更为松散的耦合,提供了更大的灵活性,而且随着站点的不断发展,更容易实现体系结构和设计的改动。
以下表格说明提供程序和控件之间的关系。
图 1. 导航体系结构
对于导航系统,数据源描述用户能够定位的 web 站点页的层次结构,以及将这些信息显示给用户的方式。它作为一个站点地图被引用。一个简单的 web 站点的布局可以是以下形式:
Home
Products
Product A
Product B
Product C
Latest Offers
Contact Us
Visit us
导航控件
在深入研究导航系统的内部工作机制之前,了解开发人员如何与之交互十分重要。最常见的方法是通过 ASP.NET 2.0 中的三个新导航控件。一个站点或页面上可以存在多个 Web 导航控件 — 如,主菜单控件放置在页面左侧,另一个菜单控件放在页面顶部,这种情况还是时有发生的,我们能够以编程方式使一个导航控件控制页面上另一个导航控件,或使它们各自独立操作。
导航系统通常与母版页功能一起使用,母版页功能也是 ASP.NET 2.0 中提供的新功能。通过将导航控件放置在站点的母版页上,可以确保整个站点具有统一的感观效果。但是,导航功能和母版页功能互不相关且各自独立。
这三个新 web 控件是:
• 菜单控件 — 它提供一个传统的导航界面,通常的情况是沿 web 站点的一侧或横跨顶部。它能够显示任意数目的嵌套子菜单,而且,当用户的鼠标停悬在某一项上时,可以显示任意数目的可选弹出子菜单。
图 2. 菜单控件
• TreeView 控件 — 它提供一个垂直的树状用户界面,通过选择单个节点可以展开和折叠用户界面。它还提供用于选定某些项的复选框功能。
图 3. TreeView 控件
• SiteMapPath 控件 — 它通常作为“breadcrumb”控件进行引用,因为它可以跟踪用户在站点层次结构内的位置。它将当前位置显示为一个路径,通常是从主页到当前位置的路径,因而用户更容易了解自己所处的位置,并定位回路径上的其他页面。
图 4. SiteMapPath 控件
从体系结构的角度来看,菜单控件和 TreeView 控件有些相似,两者之间的主要区别是编程以及显示方式不同,因此,各自拥有独特的感观效果。要详细了解这两个控件,请参阅 MSDN 中的文章 Introducing the ASP.NET 2.0 TreeView and Menu Controls。值得注意的是,虽然使用菜单控件和 TreeView 控件的最常见情况离不开站点导航,但是它们也能够用于非导航情况,这有待于用户自己做选择。
SiteMapPath (或“breadcrumb”)控件则略为不同。它直接使用 SiteMapProvider,而不是菜单控件和 TreeView 控件使用的 SiteMapDataSource 控件。这说明它是导航系统内部更有针对性的控件,因此支持将其功能扩展到非导航情况的理论依据更少。
使用导航系统
理解站点导航工作原理的一种最简单的方法是,直接在一个应用程序内部访问它,而不是通过一个 Web 控件来访问。下列代码示例说明如何与 SiteMap 对象模型进行交互以显示一部分层次结构化的站点信息。
<%@ Page Language="C#" %>
<script runat="server">
private void Page_Load(object sender, System.EventArgs e)
{
this.Label1.Text = "Current Page Title : " +
SiteMap.CurrentNode.Title;
if(SiteMap.CurrentNode.ChildNodes > 0) {
this.HyperLink1.NavigateUrl =
SiteMap.CurrentNode.ChildNodes[0].Url;
this.HyperLink1.Text =
SiteMap.CurrentNode.ChildNodes[0].Title;
}
}
</script>
<html>
<head>
</head>
<body>
<form id="Form1" runat="server">
<asp:Label ID="Label1" runat="server"
Text="Label"></asp:Label><br />
First Child Node: <asp:HyperLink id="HyperLink1"
runat="server">HyperLink</asp:HyperLink>
</form>
</body>
</html>
导航系统将站点地图模型化为一系列节点,称为 SiteMapNodes,在一个树状结构内,每个节点通常表示用户能够定位到的 web 站点上的一个页面(可能有一些节点只是子页面的占位符,或与之类似,本身没有 Web 页)。
SiteMapNode 类具有一些属性和方法,其中最重要的一些是:
• Title — 当此节点通过一个 web 控件显示时将呈现的文本
• Url — SiteMapNode 在 web 站点内表示的实际页面的 URL
• Description — 当鼠标悬停在 HTML 页面的节点上时显示的工具提示
SiteMapNode 类还有一些属性用于保存各个 SiteMapNodes 之间的关联,这些关联描述出站点地图的结构(ChildNodes、NextSibling、PreviousSibling、ParentNode 等等)。
实现您自己的站点地图提供程序
如前所述,ASP.NET 2.0 发行了一个名为 XmlSiteMapProvider 的导航数据存储提供程序,这是大部分开发人员熟悉的默认提供程序。该提供程序使用一个表示 SiteMapNodes 的 XML 文件中的数据。在使用 Visual Studio 2005 时,如果您在 Web 项目中添加了一个新站点地图,那么在默认情况下,在项目内将创建一个 Web.sitemap 文件,并按照下列模板格式进行填充。
<siteMap
xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >
<siteMapNode url="" title="" description="">
<siteMapNode url="" title="" description="" />
<siteMapNode url="" title="" description="" />
</siteMapNode>
</siteMap>
您一眼就可以看出,前面提到的核心 SiteMapNodes 属性(title、url 和 description)就是 Web.sitemap XML 架构中的属性,而且树结构(父级、子级等等)是由嵌套的 SiteMapNodes 表示的。
这是处理站点地图信息的一种简单且精练的方法,对于许多 Web 设计人员而言,使用起来绰绰有余。然而,ASP.NET 提供程序模型具有扩展性并不意味着您能够编写自己的提供程序。创建一个自定义站点地图提供程序要考虑三个可能的主要原因:
• 站点地图信息保存在一个非 XML 文件的数据源中,例如数据库或目录服务。
• 站点地图信息以 XML 的形式使用,但是使用的架构与 Web.sitemap 使用的架构不同。
• 需要一个动态的站点地图结构,该结构需要在运行时构造,或者需要一个安全剪裁不能处理的自定义视图。
为了实现您自己的站点地图提供程序,您需要从 System.Web 命名空间的 SiteMapProvider 抽象类中派生一个自定义的提供程序类。虽然 SiteMapProvider 类具有大约二十几个抽象方法或虚方法,但是在您的自定义站点地图提供程序中,只有少数方法需要重写或实现。
如果您的自定义站点地图提供程序使用的数据存储与默认的 XmlSiteMapProvider 的 Web.sitemap XML 架构相似,则应该选择从 StaticSiteMapProvider 类派生,它提供 SiteMapProvider 类的部分实现,并反过来作为实际的 XmlSiteMapProvider 类的基类。
您的类必须至少实现下列方法:
• FindSiteMapNode — 返回一个与特定 URL 对应的 SiteMapNode。
• GetChildNodes — 返回一个特定 SiteMapNode 的子节点集合。
• GetParentNode — 返回一个特定 SiteMapNode 的父节点。
• GetRootNodeCore — 返回当前提供程序目前管理的所有节点的根节点。
您还应该重写 SiteMapProvider 的 Initialize 方法,在调用基类 Initialize 之后在该方法中执行您自己的初始化。
如果有必要,您可以选择重写与节点相关的一些属性,从而构造更为复杂的表示站点地图的模型:
• SiteMapNode — 返回映射到当前 HTTPContext URL 的节点。
• RootNode — 返回存储根部的节点。
• RootProvider — 返回根部的提供程序,以允许连锁提供程序。
这些属性和方法代表了 SiteMapProvider、Menu / TreeView 控件(通过 SiteMapDataSource)和 SiteMapPath 控件之间的协定。在以下两种情况下会发生这种交互:控件请求填充显示所需的信息,以及用户通过站点进行导航以跟踪站点导航内的当前位置。它是一个事件驱动模型,在交互过程中,导航系统调入提供程序。