站點(diǎn)導(dǎo)航提供程序--ASP.NET?2.0中的站點(diǎn)導(dǎo)航提供程序暴露了應(yīng)用程序中的頁(yè)面的導(dǎo)航信息,它允許你單獨(dú)地定義站點(diǎn)的結(jié)構(gòu),而不用考慮頁(yè)面的實(shí)際物理布局。默認(rèn)的站點(diǎn)導(dǎo)航提供程序是基于XML的,但是你也可以通過(guò)編寫(xiě)自定義的提供程序,從任何后端位置暴露這些信息。
站點(diǎn)導(dǎo)航API--站點(diǎn)導(dǎo)航API用于在應(yīng)用程序的代碼中訪(fǎng)問(wèn)站點(diǎn)導(dǎo)航信息,它摘錄了導(dǎo)航信息存儲(chǔ)的細(xì)節(jié)。你可以使用API來(lái)編程訪(fǎng)問(wèn)應(yīng)用程序的導(dǎo)航節(jié)點(diǎn)。
導(dǎo)航控件--導(dǎo)航控件為頁(yè)面之間的導(dǎo)航提供了通用的UI,例如樹(shù)視圖、菜單和breadcrumb("面包屑",一種顯示當(dāng)前所在頁(yè)面的控件)。這些控件利用ASP.NET?2.0中的站點(diǎn)導(dǎo)航服務(wù)來(lái)檢索你給站點(diǎn)定義的結(jié)構(gòu)。SiteMapDataSource控件還允許你把其它UI控件綁定到站點(diǎn)導(dǎo)航數(shù)據(jù)。?
網(wǎng)站經(jīng)常需要顯示導(dǎo)航數(shù)據(jù),來(lái)指導(dǎo)用戶(hù)如何使用站點(diǎn)。ASP.NET中的導(dǎo)航特性允許開(kāi)發(fā)者簡(jiǎn)單地定義導(dǎo)航數(shù)據(jù),并根據(jù)這些信息來(lái)顯示UI。
站點(diǎn)導(dǎo)航API是一種用于訪(fǎng)問(wèn)站點(diǎn)導(dǎo)航數(shù)據(jù)的基于提供程序(provider)的編程內(nèi)容。該API把導(dǎo)航數(shù)據(jù)存儲(chǔ)在XML文件中,并通過(guò)一組SiteMapNode類(lèi)來(lái)暴露這些數(shù)據(jù)。應(yīng)用程序和控件開(kāi)發(fā)者可以構(gòu)建SiteMapNode實(shí)例并使用這些信息來(lái)顯示導(dǎo)航界面。
面向?qū)Ш降姆?wù)器控件包括Menu、TreeView、SiteMapPath和SiteMapDataSource控件。這些控件都是建立在站點(diǎn)導(dǎo)航類(lèi)的頂端的,它們使用和顯示導(dǎo)航數(shù)據(jù)的時(shí)候都是不考慮數(shù)據(jù)存儲(chǔ)的特定細(xì)節(jié)問(wèn)題的。Menu和TreeView控件還可以使用XML文件的數(shù)據(jù)和XMLDataSource控件的數(shù)據(jù)。
Url映射特性允許開(kāi)發(fā)者為不同URL請(qǐng)求的重映射(re-mapping)定義簡(jiǎn)單的規(guī)則。
使用站點(diǎn)導(dǎo)航控件
Menu、TreeView、SiteMapPath和SiteMapDataSource控件根據(jù)導(dǎo)航數(shù)據(jù)生成導(dǎo)航界面。導(dǎo)航數(shù)據(jù)可以存儲(chǔ)在XML文件中,或者利用站點(diǎn)導(dǎo)航特性的基于提供程序的能力來(lái)保存。下面的例子演示了如何組合使用站點(diǎn)導(dǎo)航特性的不同控件。
建立應(yīng)用程序站點(diǎn)地圖
示例的導(dǎo)航結(jié)構(gòu)存放在Web.sitemap文件中,在下面你可以看到站點(diǎn)地圖文件。Web.sitemap文件包含一個(gè)頂層的<siteMap>元素。在<siteMap>元素內(nèi)至少嵌套一個(gè)<siteMapNode>元素。在一個(gè)站點(diǎn)地圖內(nèi)必須有一個(gè)頂層的<siteMapNode>。站點(diǎn)導(dǎo)航特性需要一個(gè)根<siteMapNode>來(lái)確保沿著節(jié)點(diǎn)層次的訪(fǎng)問(wèn)最終匯聚到一個(gè)已知的節(jié)點(diǎn)。你可以在根<siteMapNode>元素下嵌套多個(gè)<siteMapNode>元素。此外,嵌套<siteMapNode>元素的深度是沒(méi)有限制的。
一個(gè)<siteMapNode>元素通常包含Url(鏈接)、Title(標(biāo)題)和Description(描述)屬性。Url屬性指明與應(yīng)用程序中的頁(yè)面對(duì)應(yīng)的路徑。它也可以包含其它應(yīng)用程序中的頁(yè)面的路徑,或者指向完全不同的網(wǎng)站的多個(gè)URL。在下面的例子中,所有的Url屬性都使用應(yīng)用程序相對(duì)語(yǔ)法來(lái)引用路徑。Title屬性用于顯示導(dǎo)航數(shù)據(jù)UI的文本內(nèi)容。例如,SiteMapPath控件把Title屬性作為控件的超鏈接文本顯示。如果提供了Description屬性,服務(wù)器控件就把顯示為工具條提示或ALT文本。開(kāi)發(fā)者也可以給<siteMapNode>添加自定義屬性,利用SiteMapNode類(lèi)的默認(rèn)索引器(indexer)就可以檢索這些屬性了。你可以查閱.NET框架組件文檔找到更多的關(guān)于<siteMapNode>元素其它一些屬性的信息。
Web.sitemap的內(nèi)容
<siteMap>
<siteMapNode?title="Home"?url="~/default.aspx"?>
<siteMapNode?title="Introduction?to?ASP.NET"?url="~/introduction/default.aspx">
<siteMapNode?title="What's?New?in?Whidbey?"?url="~/introduction/whatsnew.aspx"/>
<siteMapNode?title="Sample?Applications?(Starter?Kits)"?url="~/introduction/starterkits.aspx"/>
<siteMapNode?title="Introduction?to?Visual?Web?Developer"?url="~/introduction/vwd.aspx"/>
</siteMapNode>
<siteMapNode?title="Building?A?Web?Application"?url="~/development/default.aspx">
<siteMapNode?title="Building?a?Simple?Application"?url="~/development/simple/default.aspx">
<siteMapNode?title="Introduction?to?ASP.NET?pages"?url="~/development/simple/pages.aspx"/>
……
</siteMapNode>
</siteMapNode>
</siteMap>
使用站點(diǎn)導(dǎo)航控件
在Web頁(yè)面上提供站點(diǎn)導(dǎo)航的最簡(jiǎn)單辦法就是使用圖形化的站點(diǎn)導(dǎo)航控件(SiteMapPath、TreeView和?Menu)。
·?SiteMapPath--一個(gè)breadcrumb控件,它檢索用戶(hù)的當(dāng)前頁(yè)面并顯示頁(yè)面的層次結(jié)構(gòu)。這讓用戶(hù)可以導(dǎo)航回層次中其它的頁(yè)面。SiteMapPath只能與SiteMapProvider一起使用,需要設(shè)置控件的SiteMapProvider屬性。
·?TreeView--在Web頁(yè)面上提供垂直的用戶(hù)界面,它可以展開(kāi)和收縮選中的節(jié)點(diǎn),也可以提供檢查框功能以供用戶(hù)選擇數(shù)據(jù)項(xiàng)。TreeView控件支持宣告式的或編程設(shè)置數(shù)據(jù)元素和數(shù)據(jù)源控件。如果你使用SiteMapDataSource控件,那么數(shù)據(jù)綁定就是自動(dòng)進(jìn)行的。
·?Menu--提供水平的或垂直的用戶(hù)界面,當(dāng)用戶(hù)把鼠標(biāo)放在一項(xiàng)上的時(shí)候會(huì)彈出子菜單。Menu控件支持宣告式的或編程設(shè)置數(shù)據(jù)元素或數(shù)據(jù)源控件。如果你使用SiteMapDataSource控件,數(shù)據(jù)綁定就是自動(dòng)進(jìn)行的。
請(qǐng)注意,TreeView和Menu控件都可以用于非導(dǎo)航的情形。
下表描述了TreeView和Menu之間的差別,以便于你能根據(jù)需要做出適當(dāng)?shù)倪x擇。
特性?Menu?TreeView?
擴(kuò)展?彈出?位置擴(kuò)展?
根據(jù)需要下載?No?Yes?
檢查框?No?Yes?
模板?Yes?No?
布局?水平?&?垂直?垂直?
Style選項(xiàng)?Yes?Yes?
選擇模式?靜態(tài)的、?動(dòng)態(tài)的層次?層次或父/根/葉,或按數(shù)據(jù)項(xiàng)?
在下面的例子中,你看到的TreeView和Menu控件為不同的區(qū)域和操作(例如NodeStyle和HoverNodeStyle)配置了一些樣式屬性。例子中的TreeView和Menu控件都連接到頁(yè)面上的同一個(gè)SiteMapDataSource控件。SiteMapPath控件通過(guò)Web.config文件中設(shè)置的默認(rèn)的SiteMapProvider來(lái)訪(fǎng)問(wèn)相同的數(shù)據(jù)。
<asp:treeview?ID="TreeView1"?ForeColor="White"?DataSourceId="SiteMapDataSource1"?NodeIndent="0"?NodeStyle-ChildNodesPadding="10"?runat="server">
<LevelStyles>
<asp:TreeNodeStyle?Font-Bold="true"/>
<asp:TreeNodeStyle?/>
<asp:TreeNodeStyle?Font-Size="x-small"/>
</LevelStyles>
<nodestyle?forecolor="White"?HorizontalPadding="5"/>
<SelectedNodeStyle?backcolor="lightblue"?forecolor="blue"?/>
<HoverNodeStyle?Font-UnderLine="true"?/>
</asp:treeview>
<asp:sitemappath?id="SiteMapPath1"?runat="server"?/>
<asp:Menu?ID="Menu1"?DataSourceId="SiteMapDataSource1"?runat="server">
<DynamicSelectedStyle?BackColor="lightblue"?ForeColor="Blue"?/>
<DynamicHoverStyle?Font-Underline="true"?/>
<StaticHoverStyle?Font-Underline="true"?/>
</asp:Menu>
<asp:sitemapdatasource?id="SiteMapDataSource1"?runat="server"?/>
使用站點(diǎn)導(dǎo)航API
站點(diǎn)導(dǎo)航API是使用可配置的提供程序訪(fǎng)問(wèn)導(dǎo)航數(shù)據(jù)的編程抽象內(nèi)容。站點(diǎn)導(dǎo)航提供程序把導(dǎo)航數(shù)據(jù)的存儲(chǔ)細(xì)節(jié)信息與API的其它部分隔離開(kāi)來(lái)。站點(diǎn)導(dǎo)航API通過(guò)SiteMap和SiteMapNode類(lèi)來(lái)暴露導(dǎo)航數(shù)據(jù)。SiteMap類(lèi)返回與當(dāng)前頁(yè)面對(duì)應(yīng)的SiteMapNode實(shí)例。它還可以訪(fǎng)問(wèn)那些為站點(diǎn)導(dǎo)航特性配置的提供程序。SiteMapProvider為執(zhí)行下面一些事務(wù)提供了豐富的API:
·?依據(jù)當(dāng)前的HttpContext或任意URL檢索SiteMapNode實(shí)例。
·?檢索SiteMapNode的父或子節(jié)點(diǎn)。
·?訪(fǎng)問(wèn)當(dāng)前頁(yè)面的SiteMapNode,以及整個(gè)導(dǎo)航層次中的根SiteMapNode。
·?執(zhí)行授權(quán)規(guī)則,這樣就保證了提供程序只返回用戶(hù)可以看見(jiàn)的節(jié)點(diǎn)。
SiteMapNode實(shí)例暴露的基本導(dǎo)航信息和功能包括:
·?URL、Title和description屬性,以及開(kāi)發(fā)者給SiteMapNode添加的自定義屬性。
·?獲取某個(gè)節(jié)點(diǎn)的父和子節(jié)點(diǎn)。
·?在某個(gè)節(jié)點(diǎn)的前后節(jié)點(diǎn)之間進(jìn)行導(dǎo)航。
·?獲取SiteMapProvider實(shí)例的指針,它返回一個(gè)節(jié)點(diǎn)。
ASP.NET發(fā)布的時(shí)候帶有XmlSiteMapProvider提供程序。該提供程序使用XML文件(web.sitemap)中的數(shù)據(jù),并根據(jù)數(shù)據(jù)返回SiteMapNode實(shí)例。XmlSiteMapProvider有下面一些功能:
·?多個(gè)站點(diǎn)地圖(sitemap)文件可以鏈接在一起來(lái)構(gòu)建一個(gè)"虛擬的"導(dǎo)航數(shù)據(jù)集合。
·?多個(gè)XmlSiteMapProvider實(shí)例可以鏈接到一起來(lái)構(gòu)建一個(gè)"虛擬的"導(dǎo)航數(shù)據(jù)集合。
·?提供程序可以根據(jù)站點(diǎn)當(dāng)前的文件授權(quán)和URL授權(quán)規(guī)則來(lái)返回過(guò)慮后的節(jié)點(diǎn)。
有了SiteMapProvider指針之后,你就可以根據(jù)URL來(lái)檢索特定節(jié)點(diǎn)的站點(diǎn)導(dǎo)航數(shù)據(jù)。它會(huì)讓你獲取站點(diǎn)導(dǎo)航數(shù)據(jù)中的SiteMapNode實(shí)例指針。可以檢索任意SiteMapNode實(shí)例的能力和從任何SiteMapNode開(kāi)始進(jìn)行站點(diǎn)導(dǎo)航的能力組合在一起,使你能夠輕易地遍歷站點(diǎn)的導(dǎo)航數(shù)據(jù)。
作為一名開(kāi)發(fā)者,你也可以把導(dǎo)航數(shù)據(jù)用其它的格式進(jìn)行存儲(chǔ)(例如作為關(guān)系數(shù)據(jù)存儲(chǔ)在數(shù)據(jù)庫(kù)中)。接著你應(yīng)該構(gòu)建一個(gè)衍生自SiteMapProvider的自定義提供程序。
使用站點(diǎn)導(dǎo)航類(lèi)編程
你可以在代碼中編程獲取導(dǎo)航數(shù)據(jù)。編程獲取站點(diǎn)導(dǎo)航數(shù)據(jù)的出發(fā)點(diǎn)是SiteMap類(lèi)。在這個(gè)類(lèi)中有大量的靜態(tài)方法,其中最重要的一個(gè)是CurrentNode屬性。在網(wǎng)站的任何頁(yè)面中,你都可以調(diào)用SiteMap.CurrentNode來(lái)引用與當(dāng)前的執(zhí)行頁(yè)面相匹配的導(dǎo)航數(shù)據(jù)片斷。導(dǎo)航數(shù)據(jù)是用SiteMapNode實(shí)例的形式返回的--當(dāng)你調(diào)用SiteMap.CurrentNode的時(shí)候,該屬性返回與當(dāng)前頁(yè)面對(duì)應(yīng)的SiteMapNode實(shí)例。站點(diǎn)導(dǎo)航特性根據(jù)存儲(chǔ)在XML文件中的導(dǎo)航數(shù)據(jù)返回正確的節(jié)點(diǎn)。
下面的例子演示了一個(gè)帶有簡(jiǎn)單的分頁(yè)功能的用戶(hù)控件。在顯示的頁(yè)面中,用戶(hù)控件位于頁(yè)面的底部中間。最初該鏈接的內(nèi)容是"下一個(gè)主題"。當(dāng)你點(diǎn)擊這個(gè)鏈接的時(shí)候,用戶(hù)控件調(diào)用SiteMapNode對(duì)象來(lái)檢測(cè)當(dāng)前頁(yè)面的附近是否存在頁(yè)面。代碼檢測(cè)SiteMap.CurrentNode屬性,看它的前面是否有頁(yè)面(SiteMap.CurrentNode.PreviousSibling)、它的后面是否有頁(yè)面(SiteMap.CurrentNode.NextSibling)。如果存在頁(yè)面,用戶(hù)控件就顯示超鏈接,并把超鏈接的NavigateUrl屬性設(shè)置為附近節(jié)點(diǎn)的Url屬性。
如果你點(diǎn)擊頁(yè)面左部的Treeview鏈接,可以看到用戶(hù)控件是如何自動(dòng)地顯示適當(dāng)?shù)?前一個(gè)主題"和"后一個(gè)主題"鏈接的。用戶(hù)控件還顯示了另外一個(gè)超鏈接,你可以點(diǎn)擊它返回主頁(yè)。如果你查看這個(gè)超鏈接如何工作就會(huì)發(fā)現(xiàn),該控件利用了主頁(yè)<siteMapNode>元素中的自定義屬性"customAttribute"。該控件演示了如何使用SiteMapNode的默認(rèn)索引器來(lái)檢索自定義屬性的值。
<script?language="VB"?runat="server">
Sub?Page_Load()
If?(Not?SiteMap.CurrentNode.NextSibling?Is?Nothing)?Then
NextTopic.NavigateUrl?=?SiteMap.CurrentNode.NextSibling.Url
Else
NextTopic.Visible?=?false
Separator.Visible?=?false
End?If
If?(Not?SiteMap.CurrentNode.PreviousSibling?Is?Nothing)
PrevTopic.NavigateUrl?=?SiteMap.CurrentNode.PreviousSibling.Url
Else
PrevTopic.Visible?=?false
Separator.Visible?=?false
End?If
'使用FindSiteMapNode查找URL中的節(jié)點(diǎn)并提取一些信息
Dim?rootNode?as?SiteMapNode?=?SiteMap.Provider.FindSiteMapNode("~/Home.aspx")
GoHome.NavigateUrl?=?rootNode.Url
GoHome.ToolTip?=?rootNode.Description
GoHome.Text?=?rootNode("customAttribute")
End?Sub
</script>
站點(diǎn)導(dǎo)航的安全性
站點(diǎn)導(dǎo)航特性可以根據(jù)授權(quán)規(guī)則過(guò)慮提供程序所返回的SiteMapNode實(shí)例。XmlSiteMapProvider可以根據(jù)當(dāng)前網(wǎng)站使用的文件和URL授權(quán)規(guī)則過(guò)慮節(jié)點(diǎn)。
下面的例子使用了窗體授權(quán)規(guī)則,預(yù)定義的用戶(hù)憑證存儲(chǔ)在web.config中。在global.asax中,根據(jù)用戶(hù)名,用戶(hù)的角色都被附加到當(dāng)前的請(qǐng)求上。在web.config中,嵌套在<siteMap>元素之下的站點(diǎn)地圖提供程序使用的<add>元素的securityTrimmingEnabled屬性被設(shè)置為真。同時(shí),web.config文件的末尾定義了一組URL授權(quán)規(guī)則。當(dāng)你運(yùn)行示例并登陸之后,XmlSiteMapProvider會(huì)自動(dòng)地依據(jù)用戶(hù)所屬的角色和web.config中定義的授權(quán)規(guī)則來(lái)對(duì)SiteMapNode執(zhí)行授權(quán)檢測(cè)。
請(qǐng)使用下面三個(gè)帳戶(hù)之一運(yùn)行示例:
·?Userid:?SectionOne?Password:?SectionOne?
·?Userid:?SectionTwo?Password:?SectionTwo?
·?Userid:?AllSections?Password:?AllSections?
在頁(yè)面的右上角有一個(gè)"退出"鏈接,因此你可以用不同的帳號(hào)登陸和退出。請(qǐng)注意,根據(jù)你登陸所使用的帳號(hào)不同,導(dǎo)航UI顯示的Treeview和Menu控件會(huì)自動(dòng)地反映該用戶(hù)所獲得的訪(fǎng)問(wèn)權(quán)限。提供程序自動(dòng)地過(guò)慮了返回的節(jié)點(diǎn)--實(shí)現(xiàn)這種功能不需要額外的代碼。用"SectionOne"帳號(hào)登陸的時(shí)候,只在左邊的Treeview控件中顯示"SectionOne"鏈接和外部鏈接。用"SectionTwo"帳號(hào)登陸的時(shí)候,只在左邊的Treeview控件中顯示"SectionTwo"鏈接和外部鏈接。用"AllSections"帳號(hào)登陸的時(shí)候,Treeview控件中顯示了所有的鏈接。web.config中的授權(quán)規(guī)則配置為給"SectionOne"和"SectionTwo"層次授予了部分訪(fǎng)問(wèn)權(quán)力。
這個(gè)示例還演示了如何處理應(yīng)用程序目錄范圍之外的URL安全性。在web.sitemap文件中,外部鏈接的節(jié)點(diǎn)使用了roles屬性。語(yǔ)法roles="*"授予所有用戶(hù)訪(fǎng)問(wèn)和查看導(dǎo)航控件中的節(jié)點(diǎn)的權(quán)力。語(yǔ)法roles="Adminstrators,Regular?Users"只允許這些角色的用戶(hù)檢索和查看導(dǎo)航控件中的節(jié)點(diǎn)。由于在示例中g(shù)lobal.asax文件把用戶(hù)分成了這兩種角色,所以你一直可以看到外部鏈接。
開(kāi)發(fā)者可以選擇同時(shí)使用文件/URL授權(quán)規(guī)則和roles屬性來(lái)控制用戶(hù)對(duì)SiteMapNode實(shí)例的訪(fǎng)問(wèn)權(quán)。如果兩者的設(shè)置信息都是正確的,站點(diǎn)導(dǎo)航提供程序就會(huì)根據(jù)文件/URL授權(quán)規(guī)則和roles屬性中的角色來(lái)對(duì)當(dāng)前用戶(hù)進(jìn)行認(rèn)證。如果當(dāng)前用戶(hù)通過(guò)了任何一種授權(quán)檢查,就可以訪(fǎng)問(wèn)節(jié)點(diǎn)。
如果默認(rèn)的安全性操作不適用于你的應(yīng)用程序,開(kāi)發(fā)者還可以從XmlSiteMapProvider衍生類(lèi),并用自定義的節(jié)點(diǎn)授權(quán)實(shí)現(xiàn)來(lái)重載IsAccessibleToUser方法。
Web.config的內(nèi)容
<system.web>
<authentication?mode="Forms">
<forms?name=".ASPXAUTH"?loginUrl="Login.aspx"?protection="All"?timeout="30"?path="/"?requireSSL="false"?slidingExpiration="true"?defaultUrl="Home.aspx"?cookieless="UseCookies"?enableCrossAppRedirects="false">
<credentials?passwordFormat="Clear">
<user?name="SectionOne"?password="SectionOne"/>
<user?name="SectionTwo"?password="SectionTwo"/>
<user?name="AllSections"?password="AllSections"/>
</credentials>
</forms>
</authentication>
<authorization>
<deny?users="?"/>
</authorization>
</system.web>
<location?path="SectionOne.aspx">
<system.web>
<authorization>
<allow?users="SectionOne"?roles="Administrators"?/>
<deny?users="*"/>
</authorization>
</system.web>
</location>
<location?path="SectionOne">
<system.web>
<authorization>
<allow?users="SectionOne"?roles="Administrators"/>
<deny?users="*"/>
</authorization>
</system.web>
</location>
<location?path="SectionTwo.aspx">
<system.web>
<authorization>
<allow?users="SectionTwo"?roles="Administrators"/>
<deny?users="*"/>
</authorization>
</system.web>
</location>
<location?path="SectionTwo">
<system.web>
<authorization>
<allow?users="SectionTwo"?roles="Administrators"/>
<deny?users="*"/>
</authorization>
</system.web>
本地化站點(diǎn)地圖數(shù)據(jù)
存儲(chǔ)在sitemap文件中的導(dǎo)航數(shù)據(jù)可能需要進(jìn)行本地化(localize)。<siteMapNode>元素中的URL、Title和Description屬性也可以本地化。此外,開(kāi)發(fā)者放置在<siteMapNode>元素中的任何自定義屬性也可以本地化。
下面的示例包含了英語(yǔ)和法語(yǔ)的本地化文本。它的web.sitemap文件使用兩種類(lèi)型(隱式的和顯式的)的本地化表達(dá)式來(lái)實(shí)現(xiàn)這種功能。Sitemap文件在根siteMap元素中使用了enableLocalization=true就表明它使用了本地化數(shù)據(jù)。
站點(diǎn)地圖文件的隱式表達(dá)式讓開(kāi)發(fā)者能夠輕易地用查找鍵(lookup?key)標(biāo)記每個(gè)<siteMapNode>元素,而查找鍵是用于從資源文件檢索資源的。在示例的web.sitemap中,除了第一個(gè)節(jié)點(diǎn)之外,所有的節(jié)點(diǎn)都有隱式的資源表達(dá)式。它的語(yǔ)法類(lèi)似resourceKey="Autos"。當(dāng)XmlSiteMapProvider根據(jù)web.sitemap文件中的信息檢索SiteMapNode的時(shí)候,它根據(jù)SiteMapNode屬性的名稱(chēng)、resourceKey和為提供程序配置的siteMapFile屬性的值來(lái)檢索字符串資源。使用示例中的"Autos"節(jié)點(diǎn)的時(shí)候,提供程序(provider)會(huì)根據(jù)當(dāng)前的文化來(lái)查找以"web.sitemap"開(kāi)頭的資源文件。這意味著,對(duì)于一個(gè)發(fā)送法語(yǔ)頭信息的瀏覽器來(lái)說(shuō),提供程序會(huì)查找名稱(chēng)為web.sitemap.fr.resx的資源文件。在這個(gè)資源文件中,提供程序會(huì)依據(jù)resourceKey?+?"."?+?[SiteMapNode屬性名]來(lái)查找資源鍵。例如,把"Autos"節(jié)點(diǎn)的Title屬性當(dāng)作例子,提供程序會(huì)在web.sitemap.fr.resx資源文件中查找鍵為Autos.Title的資源。
顯式表達(dá)式使開(kāi)發(fā)者對(duì)包含本地資源的文件和資源鍵(resource?key)的名稱(chēng)有更強(qiáng)的控制能力。在示例web.sitemap中,第一個(gè)<siteMapNode>元素使用了顯式資源表達(dá)式。顯式表達(dá)式在每個(gè)屬性上指定。第一個(gè)<siteMapNode>元素的Title屬性使用了顯式表達(dá)式。顯式表達(dá)式必須以$resource:開(kāi)頭。在這個(gè)標(biāo)識(shí)符之后,開(kāi)發(fā)者必須提供資源文件的根名稱(chēng)和資源鍵。開(kāi)發(fā)者可以選擇提供一個(gè)默認(rèn)值。在例子中,表達(dá)式$resources:?Title,?MyTitle?,?Home表明提供程序應(yīng)該查看以"Title"開(kāi)頭的資源文件。對(duì)于發(fā)送法語(yǔ)頭信息的瀏覽器開(kāi)說(shuō),提供程序會(huì)查找Title.fr.resx資源文件。接下來(lái)提供程序查看鍵為MyTitle的資源。如果提供程序無(wú)法找到這種資源,它會(huì)把字符串"Home"作為默認(rèn)值。
你可以運(yùn)行示例來(lái)查看站點(diǎn)地圖本地化的效果。把英語(yǔ)作為默認(rèn)語(yǔ)言的瀏覽器會(huì)顯式英語(yǔ)文本。如果使用IE,你可以通過(guò)點(diǎn)擊"工具->Internet選項(xiàng)",并在"通用"選項(xiàng)卡點(diǎn)擊"語(yǔ)言"按鈕,點(diǎn)擊"添加"按鈕并選擇添加"法語(yǔ)"。如果需要,還需要選中法語(yǔ)并點(diǎn)擊"向上移動(dòng)"按鈕,使它成為IE的默認(rèn)請(qǐng)求語(yǔ)言。把默認(rèn)的語(yǔ)言改成法語(yǔ)之后,刷新示例頁(yè)面。請(qǐng)注意,Menu、Treeview和SiteMapPath控件中的文本自動(dòng)地顯式為App_GlobalResources目錄中存放的法語(yǔ)資源文件中的法語(yǔ)文本。
Web.sitemap的內(nèi)容
<?xml?version="1.0"?encoding="utf-8"??>
<siteMap?xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0"?enableLocalization="true">
<siteMapNode?url="~/Default.aspx"?title="?$resources:?Title,?MyTitle?,?Home"?description="Default?page?description?when?no?localized?value?exists."?>
<siteMapNode?url="~/Category.aspx"?resourceKey="Category">
<siteMapNode?title="Autos"?description="Autos"?url="~/Autos.aspx"?resourceKey="Autos"?/>
<siteMapNode?title="Games"?description="Games"?url="~/Games.aspx"?resourceKey="Games"?/>
<siteMapNode?title="Health"?description="Health"?url="~/Health.aspx"?resourceKey="Health"?/>
<siteMapNode?title="News"?description="News"?url="~/News.aspx"?resourceKey="News"?/>
</siteMapNode>
</siteMapNode>
</siteMap>
修改提供程序(Provider)返回的站點(diǎn)導(dǎo)航數(shù)據(jù)
存儲(chǔ)在web.sitemap中、供XmlSiteMapProvider使用的導(dǎo)航數(shù)據(jù)是靜態(tài)的--這些數(shù)據(jù)被載入內(nèi)存中并作為只讀數(shù)據(jù)存儲(chǔ)。但是,很多站點(diǎn)的導(dǎo)航結(jié)構(gòu)是根據(jù)查詢(xún)字符串的值來(lái)參數(shù)化的。例如,新聞組(newsgroup)站點(diǎn)可能擁有良好定義的頁(yè)面結(jié)構(gòu)(例如,主頁(yè)、新聞?lì)悇e頁(yè)面和新聞內(nèi)容頁(yè)面),但是實(shí)際的內(nèi)容可能會(huì)有很大的不同,這依賴(lài)于查詢(xún)字符串中的標(biāo)識(shí)符。盡管把每種可能的查詢(xún)字符串值都存儲(chǔ)在<siteMapNode>元素中也是可能的,但是即使是中等數(shù)量的查詢(xún)字符串值,也要求sitemap文件包含數(shù)百個(gè)<siteMapNode>元素。
站點(diǎn)導(dǎo)航特性在SiteMapProvider基類(lèi)中暴露了SiteMapResolve事件。可以使用SiteMap.SiteMapResolve或直接使用提供程序SiteMap.Provider.SiteMapResolve來(lái)執(zhí)行這個(gè)事件。這個(gè)事件的返回值是一個(gè)SiteMapNode實(shí)例。你可以在自己的事件處理程序中編寫(xiě)自定義邏輯來(lái)建立SiteMapNode實(shí)例的層次結(jié)構(gòu)。這個(gè)邏輯可以修改每個(gè)SiteMapNode的屬性,因此URL和Title等屬性會(huì)反映查詢(xún)字符串帶有的數(shù)據(jù)信息。
下面的例子在global.asax中注冊(cè)了一個(gè)事件處理程序。這個(gè)事件處理程序的代碼是App_Code目錄中的一個(gè)類(lèi)。這個(gè)自定義的類(lèi)復(fù)制與當(dāng)前頁(yè)面對(duì)應(yīng)的SiteMapNode實(shí)例。XmlSiteMapProvider返回的節(jié)點(diǎn)都是只讀的,而調(diào)用SiteMapNode上的Clone方法返回的是可寫(xiě)入的節(jié)點(diǎn)。在實(shí)例中,如果給Clone傳遞了true值,將導(dǎo)致當(dāng)前的SiteMapNode和它的所有父節(jié)點(diǎn)都是可寫(xiě)入的。這個(gè)類(lèi)的代碼的其它部分檢查當(dāng)前的頁(yè)面和當(dāng)前頁(yè)面的查詢(xún)字符串,確定當(dāng)前頁(yè)面位于站點(diǎn)層次結(jié)構(gòu)的什么位置。代碼修改了URL和Title屬性,包含一些額外的信息,這樣SiteMapPath控件顯示的導(dǎo)航UI就反映了網(wǎng)站用戶(hù)為到達(dá)當(dāng)前頁(yè)面的實(shí)際點(diǎn)擊路徑。
運(yùn)行示例的時(shí)候,你開(kāi)始位于站點(diǎn)的主頁(yè)。SiteMapPath控件也反映了這一點(diǎn)。點(diǎn)擊任何鏈接都會(huì)帶你進(jìn)入分類(lèi)頁(yè)面,它顯示相關(guān)新聞?lì)悇e中的新聞鏈接。請(qǐng)注意,如果你把鼠標(biāo)停留在SiteMapPath控件的最后一個(gè)鏈接上,瀏覽器狀態(tài)欄中顯示的URL包含了查詢(xún)字符串信息(它指定了新聞?lì)悇e)。點(diǎn)擊任何一個(gè)發(fā)布鏈接都會(huì)把你帶回到新聞發(fā)布頁(yè)面。如果你把鼠標(biāo)停留SiteMapPath控件的鏈接上,可以注意到控件中的最后兩個(gè)鏈接帶有的URL和Title包含了點(diǎn)擊路徑的正確查詢(xún)字符串和描述信息。如果你導(dǎo)航到站點(diǎn)的主頁(yè),并點(diǎn)擊其它的新聞組和內(nèi)容鏈接,SiteMapPath控件會(huì)被更新并反映第二次點(diǎn)擊的鏈接。
Public?Class?PathExpansionHandler
Public?Shared?Function?ExpandPath(ByVal?sender?As?Object,?ByVal?e?As?SiteMapResolveEventArgs)?As?SiteMapNode
'獲取當(dāng)前和之前節(jié)點(diǎn)的引用
Dim?nodeCopy?As?SiteMapNode?=?SiteMap.CurrentNode.Clone(True)?
Dim?tempNode?As?SiteMapNode?=?nodeCopy?
'Check?if?there?is?a?newsgroup?type?in?the?query?string
Dim?typeID?As?String?=?Nothing?
Dim?typeIDUrlEncoded?As?String?=?Nothing?
If?Not?String.IsNullOrEmpty(e.Context.Request.QueryString("type"))?Then
typeID?=?e.Context.Server.HtmlEncode(e.Context.Request.QueryString("type"))
typeIDUrlEncoded?=?e.Context.Server.UrlEncode(e.Context.Request.QueryString("type"))
End?If
'首先執(zhí)行發(fā)布頁(yè)面URL的固定
'如果查詢(xún)字符串中包含發(fā)布ID,我們就知道當(dāng)前節(jié)點(diǎn)式發(fā)布頁(yè)面
If?Not?String.IsNullOrEmpty(e.Context.Request.QueryString("postingID"))?Then
Dim?postingID?as?string?=?_
e.Context.Server.HtmlEncode(e.Context.Request.QueryString("postingID"))
Dim?postingIDUrlEncoded?as?string?=?_
e.Context.Server.UrlEncode(e.Context.Request.QueryString("postingID"))
Dim?NewUrl?As?String?=?tempNode.Url?+?"?type="?+?typeIDUrlEncoded?+?"&postingID="?+?postingIDUrlEncoded?
Dim?NewTitle?As?String?=?tempNode.Title?+?":?"?+?postingID?
tempNode.Url?=?NewUrl
tempNode.Title?=?NewTitle
tempNode?=?tempNode.ParentNode
End?If
'然后,對(duì)新聞組頁(yè)面進(jìn)行固定
'這時(shí)候nodeCopy?變量知賢了新聞組節(jié)點(diǎn)
If?Not?String.IsNullOrEmpty(e.Context.Request.QueryString("type"))?Then
Dim?NewUrl?As?String?=?tempNode.Url?+?"?type="?+?typeIDUrlEncoded?
Dim?NewTitle?As?String?=?tempNode.Title?+?":?"?+?typeID?
tempNode.Url?=?NewUrl
tempNode.Title?=?NewTitle
End?If
'最后返回當(dāng)前節(jié)點(diǎn)
Return?nodeCopy
End?Function
End?Class
URL映射
URL映射特性利用web.config中存儲(chǔ)的配置信息把收到的請(qǐng)求重映射(remap)到不同的URL。重映射發(fā)生在對(duì)請(qǐng)求的所有其它處理操作之前。下面的例子演示的是重映射一個(gè)頁(yè)面請(qǐng)求,實(shí)際上任意文件類(lèi)型都可以把請(qǐng)求重映射到不同的URL。
定義重映射URL
URL映射的配置信息存儲(chǔ)在web.config中。<urlMappings?>元素中嵌套的每個(gè)<add>元素為重映射進(jìn)入站點(diǎn)的(inbound)url定義了一條規(guī)則。url屬性定義了進(jìn)入站點(diǎn)的url的exact(原樣)屬性,URL映射特性會(huì)試圖用它進(jìn)行匹配操作。如果exact匹配操作發(fā)生了,就會(huì)給進(jìn)入站點(diǎn)的URL重新寫(xiě)入mappedUrl屬性值。請(qǐng)注意,這個(gè)特性不支持更高級(jí)的規(guī)則(例如基于通配符和正則表達(dá)式的匹配)。?
示例web.config為大量的url定義了映射規(guī)則。示例使用的web.sitemap文件定義的大量帶有URL值的節(jié)點(diǎn)都會(huì)被重映射。其結(jié)果是,URL映射和站點(diǎn)導(dǎo)航的組合使用,使得開(kāi)發(fā)者可以用友好的url來(lái)定義導(dǎo)航結(jié)構(gòu),并使用URL映射把請(qǐng)求重新寫(xiě)到不同的頁(yè)面來(lái)執(zhí)行實(shí)際的處理過(guò)程。
當(dāng)你運(yùn)行示例的時(shí)候,請(qǐng)注意Menu和Treeview控件是如何根據(jù)web.sitemap文件中定義的站點(diǎn)結(jié)構(gòu)來(lái)顯示導(dǎo)航數(shù)據(jù)的。如果你把鼠標(biāo)停留在Treeview控件或右上角的SiteMapPath控件的鏈接上方,狀態(tài)欄中顯示的url是一個(gè)友好的url鏈接。當(dāng)你點(diǎn)擊任何導(dǎo)航鏈接的時(shí)候,實(shí)際運(yùn)行的頁(yè)面是Default.aspx。但是,Menu、Treeview和SiteMapPath控件中的導(dǎo)航信息仍然反映為友好的URL結(jié)構(gòu)。
在頁(yè)面的底部你還可以看到Request.Path、Request.QueryString["category"]和Request.RawUrl返回的值。Request.Path和Request.QueryString["category"]返回的值一直反映重映射進(jìn)入站點(diǎn)的url的結(jié)果。但是,Request.RawUrl的值反映了重映射之前的友好的url。當(dāng)站點(diǎn)導(dǎo)航特性試圖把url信息與sitemap文件包含的數(shù)據(jù)進(jìn)行匹配的時(shí)候,它會(huì)使用Request.RawUrl。如果匹配的值沒(méi)有找到,XmlSiteMapProvider就把Request.Path作為替代者。在例子中,所有的友好url在web.sitemap文件中都有條目,因此使用站點(diǎn)導(dǎo)航的控件一直根據(jù)友好的url來(lái)顯示和引用節(jié)點(diǎn)。
<?xml?version="1.0"??>
<configuration?xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<system.web>
<urlMappings?enabled="true">
<add?url="~/Category.aspx"?mappedUrl="~/Default.aspx?category=default"?/>
<add?url="~/Autos.aspx"?mappedUrl="~/Default.aspx?category=autos"?/>
<add?url="~/Games.aspx"?mappedUrl="~/Default.aspx?category=games"?/>
<add?url="~/Health.aspx"?mappedUrl="~/Default.aspx?category=health"?/>
<add?url="~/News.aspx"?mappedUrl="~/Default.aspx?category=news"?/>
</urlMappings>
</system.web>
</configuration>??