Web 站点经常使用包含查询字符串的动态 URL 地址。比如,某个新闻组或论坛中就可能同时包括指向版本或组的静态 URL 以及指向主题的动态 URL。某个指向主题的 URL 可能是这样:http://www.microsoft.com/newsgroups/ShowPost.aspx?ForumID=2&PostID=53。
想要将每个指向主题的 URL 都添加到网站地图中将会是效率极低且繁琐的任务,因为节点无法通过编程的方式进行添加。但是,当用户查看主题时,可以使用 SiteMapPath
控件来显示返回到根节点的导航路径并且动态地在每个链接中添加查询串,用来对不同的主题,论坛版块,或者新闻分组进行标识。比如,前面例示的主题导航路径可能是这样:
Home > Forum List > Post List
用于主题引用的网站地图节点的静态 Url
属性可能被设置成 http://www.microsoft.com/newsgroups/ShowPost.aspx。但是在内存中,可以通过更改 SiteMapPath
控件中的 URL 来标识不同的论坛版块和主题。
下面的步骤和例子描述了如何使用 SiteMapResolve
事件来更改内存中的网站地图节点。
在 Web 窗体页面的代码中创建一个方法来处理SiteMapResolve
事件。比如,下例代码定义并创建方法 ExpandForumPaths
。
private SiteMapNode ExpandForumPaths(Object sender, SiteMapResolveEventArgs e)
在该事件处理器中,获取当前节点的引用并复制。比如,如果该节点是新闻分组中的某个主题,对应的代码可能是这样:
SiteMapNode currentNode = SiteMap.CurrentNode.Clone(true); SiteMapNode tempNode = currentNode;
变量 tempNode
返回内存中能够跳转的网站地图节点,同时更改每个 Url
属性或其他属性。对于 nodeCopy
的引用被另外进行维护,因为事件处理器预期的返回值是对当前节点的引用,变量 tempNode
将用于进行向上的导航结构递归。
提示:因为被复制节点与静态网站导航结构分离,所以对 Url
属性的更改既不会在内存中保持也不能被写入到磁盘文件。
可以更改当前节点和当前父节点的 Url
属性集来包含主题,论坛版块,以及新闻分组的标识查询串。
比如,下例代码假设存在三个获取标识的方法。
int forumGroupID = GetMostRecentForumGroupID(); int forumID = GetMostRecentForumID(forumGroupID); int postID = GetMostRecentPostID(forumID); if (0 != postID) { tempNode.Url = tempNode.Url + "?PostID=" + postID.ToString(); } if ((null != (tempNode = tempNode.ParentNode)) && (0 != forumID)) { tempNode.Url = tempNode.Url + "?ForumID=" + forumID.ToString(); } if ((null != (tempNode = tempNode.ParentNode)) && (0 != forumGroupID)) { tempNode.Url = tempNode.Url + "?ForumGroupID=" + forumGroupID.ToString(); }
提示:if
语句用于确保查询串仅能被添加到实际存在的网站地图节点中,并且标识符是有效的新闻分组,论坛版块,以及主题的标识。
使用下例代码返回被复制的节点。
return currentNode;
在 Page_Load
方法中注册自定义事件处理器。实现代码可能是这样。
SiteMap.SiteMapResolve += new SiteMapResolveEventHandler(this.ExpandForumPaths);
提示:SiteMapResolve
事件会在网站地图提供者访问 CurrentNode
属性时被引发,比如在 SiteMapPath
控件呈现导航结构的时候。
在 Web 窗体页面中添加 SiteMapPath
控件来查看导航结构。使用 SiteMapPath
控件的代码可能是这样。
<asp:SiteMapPath id="SiteMapPath1" runat="server" RenderCurrentNodeAsLink="true" />
请确保网站地图文件中存在一个引用到 Web 窗体页面的节点。比如,如果 Web 窗体页面调用 ShowPost.aspx 时,Web.sitemap 文件的内容可能是这样。
<?xml version="1.0" encoding="utf-8" ?> <siteMap> <siteMapNode title="Forum Group" description="Forum Group List" url="default.aspx"> <siteMapNode title="Forum" description="Forum List" url="ShowForum.aspx"> <siteMapNode title="Post" description="Post List" url="ShowPost.aspx" /> </siteMapNode> </siteMapNode> </siteMap>
下例代码演示了如何在 ASP.NET Web 页面中处理 SiteMapResolve
事件并更改由 SiteMapPath
控件显示的目标 URL。在本例中,当前页面指的是某个在线公告版或论坛中的主题页面。要想呈现含有更多信息的网站导航,用 SiteMapPath
控件显示添加了相关查询串的更详细的 URL,请使用下例代码进行控件的呈现。
<asp:SiteMapPath id="SiteMapPath1" runat="server" RenderCurrentNodeAsLink="true" />
运行本例时,用鼠标移过 SiteMapPath
控件时就会发现 URL 的如何被更改的。
运行本例代码并不会在 Web.sitemap 文件中添加任何 SiteMapNode
;因为 Web.sitemap 文件只能够手动进行编辑。
提示:在 SiteMapResolveEventHandler
中对 CurrentNode
属性的访问是安全的。ASP.NET 网站导航架构会防止可能出现的无限反向递归。
本例还假设存在有效的网站地图文件,并且当前页面位于具有 3 层节点以下深度的网站地图结构中。
private void Page_Load(object sender, EventArgs e) { // The ExpandForumPaths method is called to handle // the SiteMapResolve event. SiteMap.SiteMapResolve += new SiteMapResolveEventHandler(this.ExpandForumPaths); } private SiteMapNode ExpandForumPaths(Object sender, SiteMapResolveEventArgs e) { // The current node represents a Post page in a bulletin board forum. // Clone the current node and all of its relevant parents. This // returns a site map node that a developer can then // walk, modifying each node.Url property in turn. // Since the cloned nodes are separate from the underlying // site navigation structure, the fixups that are made do not // effect the overall site navigation structure. SiteMapNode currentNode = SiteMap.CurrentNode.Clone(true); SiteMapNode tempNode = currentNode; // Obtain the recent IDs. int forumGroupID = GetMostRecentForumGroupID(); int forumID = GetMostRecentForumID(forumGroupID); int postID = GetMostRecentPostID(forumID); // The current node, and its parents, can be modified to include // dynamic querystring information relevant to the currently // executing request. if (0 != postID) { tempNode.Url = tempNode.Url + "?PostID=" + postID.ToString(); } if ((null != (tempNode = tempNode.ParentNode)) && (0 != forumID)) { tempNode.Url = tempNode.Url + "?ForumID=" + forumID.ToString(); } if ((null != (tempNode = tempNode.ParentNode)) && (0 != forumGroupID)) { tempNode.Url = tempNode.Url + "?ForumGroupID=" + forumGroupID.ToString(); } return currentNode; } ... // These methods are just placeholders for the example. // One option is to use the HttpContext or e.Content object // to obtain the ID. private int GetMostRecentForumGroupID() { return 24; } private int GetMostRecentForumID(int forumGroupId) { return 128; } private int GetMostRecentPostID(int forumId) { return 317424; }
使用查询串和窗体提交数据时的一个重要任务就是对已传递数据进行验证。ASP.NET 提供一批简单易用且功能强大的验证控件来进行错误检查,并且在必要时还会为用户显示相关错误提示。然而在前面的例子中我们并没有使用任何验证控件来关注更改网站地图节点一事。