程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> .NET實例教程 >> Scott的ASP.net MVC框架系列文章之二: URL映射

Scott的ASP.net MVC框架系列文章之二: URL映射

編輯:.NET實例教程

上個月我發表了介紹ASP.net MVC框架系列文章的第一篇,介紹了一個具有產品列表/浏覽功能的簡單的電子商務網站,包含了MVC背後的高級概念,並演示了從零開始實現如何創建一個ASP.Net MVC項目並測試了電子商務網站的產品列表功能。

在今天的這篇文章裡我將要深入介紹ASP.Net MVC框架中的URL映射架構,並討論如何在你的應用程序裡裡用這種方式進行更高級的開發。

Part1回顧

在Part1中,我們創建了一個電子商務網站並實現了一下三種URL:

URL Format

Behavior

URL Example

/Products/CategorIEs

Browse all Product CategorIEs

/Products/CategorIEs

/Products/List/Category

List Products within a Category

/Products/List/Beverages

/Products/Detail/ProductID

Show Details about a Specific Product

/Products/Detail/34

我們創建了ProductController類實現對這些URL的處理:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130177.jpg

上面的類被加入我們的應用程序後,ASP.Net MVC框架自動處理URL請求並選擇控制類中相應的操作方法進行處理。

今天的文章裡我們將要深入探討ASP.Net MVC框架URL映射的工作機制和高級應用,我將演示如何對URL映射進行單元測試。

ASP.Net MVC URL映射系統的功能

ASP.Net MVC框架包含一個復雜的URL映射系統,你可以在其中自己定義映射規則,映射系統有兩個主要的功能:

  1. 正確解析傳入的 URL請求並定位到正確的控制類和控制方法進行處理
  2. 構建輸出的用於調用控制類/操作方法的URL路徑(例如:提交表單, <a href=””>鏈接,以及AJax調用)

URL映射規則提供的解析傳入URL和生成輸出URL的功能增強了應用程序的靈活性,這意味著如果我們希望修改應用程序的URL結構(例如重命名/Products為/Catalog),我們只需要應用程序級別的修改映射規則而不需要修改控制類或視圖模板中的任何代碼。

ASP.Net MVC 的默認URL映射規則

當你用VisualStudio利用模板創建ASP.net MVC項目時,Global.asax文件的後台代碼中自動添加了一個ASP.Net Application類:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130230.jpg

該應用程序類是開發人員可以添加應用程序啟動/停止以及全局錯誤處理邏輯。

ASP.Net MVC項目模板默認在Application類中自動添加Application_Start方法,並在其中注冊兩條URL映射規則:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130290.jpg

上面的第一條路由規則表明ASP.Net MVC框架默認按照”[Controller]/[action]/[id]”的格式確定調用哪一個控制類實例和相應的操作方法來處理請求(同時指明了傳入的參數)。

該默認映射規則使Part 1部分提到的電子商務程序中/Products/Detail/3的請求調用ProductController類中的Detail方法並傳入3作為方法參數:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130231.jpg

前面添加的第二個映射規則用於處理應用程序中的默認頁”Default.aspx”問題(有時服務器是通過”/”方式請求默認頁的)。這條規則使得對於”Default.aspx”或”/”方式的請求都可以被HomeController類的Index()方法處理(HomeController類在使用Visual Studio根據模板創建ASP.Net MVC應用程序時被默認自動創建)。

理解映射實例

映射規則是通過向System.Web.Mvc.RouteTable中的映射集合(Routes Collection)中注冊添加新的映射實例(Route Instatnces)完成的。

Route類定義了很多用於配置映射規則的屬性,你可以通過.Net 2.0“傳統”的屬性賦值方式進行賦值:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130395.jpg

也可以通過使用VS2008 C#和VB編譯器中提供的object initializer特性進行賦值操作:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130338.jpg 

Route類的“Url”屬性定義了已被啟用並對當前請求進行處理的Url匹配規則,同時定義了如何解析URL中傳入的參數,[ParamName]定義了Url中可以變換的參數名稱,後面我們將會看到,我們並非只局限於使用已知的常用參數名稱,你可以在URL中使用任何參數名稱,例如,我使用如下一條規則"/Blogs/[Username]/Archive/[Year]/[Month]/[Day]/[Title]"處理針對Blog文章的請求,並使MVC框架自動解析傳入UserName, Year, Month, Day和Title變量,傳入控制類方法中。

Route類的”Defaults”屬性定義了一系列當傳入URL中不包含某一指定參數值情況下使用的默認值,例如,在上面的URL映射例子中我們為”[action]”和”[id]”分別定義了兩個URL參數默認值,這意味著如果應用程序接收到/Products/的請求,映射引擎將會默認調用ProductController類中的Index方法,同理,如果接收到/Products/List的請求,則null值作為ID參數的默認值。

Route類的”RouteHandler”屬性定義了當URL被相應的的URL映射規則匹配結束後用於進一步處理請求的IRouteHandler實例,在上面的例子中,我們指明了使用System.Web.Mvc.MvcRouterHandler類處理URL請求。這樣做的目的是保證URL映射引擎可以處理MVC和非MVC的請求。使用IRouteHandler接口意味著我們也可以處理非MVC請求(例如標准WebForm, Astoria REST支持等等)。

Route類還有一個”Validation”屬性,後面的文章中我們將看到這個屬性的用處,這個屬性允許我們指定根據某一規則進行匹配之前需要符合的先決條件,例如,我們可以指定某條映射規則只對某一個HTTP Verb(這讓我們可以很輕松的映射REST命令),或者我們可以在參數中使用一個正則表達式確定某條映射規則是否確實匹配。

注意:在MVC的第一個預覽版本中Route類是不可擴展的(相反它是一個數據類),在以後的版本中我們將使他可以uozhan並允許開發人員根據需要添加特殊的Route類(例如:RestRoute子類)擴展功能。

判斷映射規則

當ASP.Net MVC Web應用程序接收到URL請求時,MVC框架判斷RouteTable.Routes集合中的規則並確定使用哪個控制類處理該請求。MVC框架根據RouteTabe中映射規則的注冊順序選擇對應的控制類,URL請求與每條映射規則進行匹配,如果匹配成功則更該規則及其RouteHandler將用於處理請求(其他的規則將被忽略)。這意味著你應該按照匹配條件由多到少的順序安排你的映射規則。

映射應用:自定義搜索URL

讓我們通過實現電子商務網站的檢索功能來在看一與實際應用相應的自定義映射規則:

首先我們在項目中添加一個SearchController類:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130326.jpg

然後我們在SearchController類中定義兩個操作方法。Index()方法用於顯示包含一個用於接收用戶輸入的文本框和一個提交按鈕的檢索頁面,Result()方法用於處理表單數據,並對數據庫執行查詢和將結果顯示給用戶。

 https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130469.jpg

使用默認的/[controller]/[action]/[id]規則,我們使用下面的URL調用SearchController的操作方法:

Scenario

URL

Action Method

Search Form:

/Search/

Index

Search Results:

/Search/Results?query=Beverages

Results

 

/Search/Results?query=ASP.Net

Results

注意因為默認添加的/[controller]/[action]/[id]規則將Index()方法制定為控制類的默認方法(在”Defaults”屬性中制定),所以根路徑/Search被默認映射到Index()方法中:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130338.jpg

諸如/Search/Results?query=Beverages的URL概括了我們期望的功能,但同時我們也希望可以讓搜索結果頁具有一個更友好的URL,因此我們希望從URL中排除“Results”這一操作方法名稱,並把查詢關鍵字包含在Url中而不通過QueryString參數傳遞,例如:

Scenario

URL

Action Method

Search Form:

/Search/

Index

Search Results:

/Search/Beverages

Results

 

/Search/ASP.Net

Results

我們可以在默認的/[controller]/[action]/[id]規則前添加自定義的URL映射規則來讓搜索結果頁具備更友好的URL:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130430.jpg

我們聲明的前兩條規則指明了/Search/ 路徑的控制類和操作方法參數,我們指明/Search由SearchController的Index()方法處理,而諸如/Search/Foo, /Search/Bar的URL總是有SearchController的Result方法處理。

上面的第二條映射規則指明路徑/Search/前綴厚的部分都被作為”[query]”參數的值,並傳給SearchController類中的Result方法:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130596.jpg

我們同時希望對檢索結果進行分頁處理(每次只顯示10條數據),我們可以通過QueryString來作為參數(例如/Search/Beverages?page=2),或者可以把頁碼作為URL路徑的一部分(例如:/Search/Beverages/2)。為了實現這個特性,我們只需要在第二條映射規則中添加一個可選參數:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130574.jpg

注意新的URL映射規則是“Search/[query]/[page]”,我們同時配置了當路徑中不包含頁碼時的默認頁索引為1(通過anonymous type給“Defaults”屬性傳遞值)

我們可以更新SearchController.Results()方法把頁碼參數作為方法變量。

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130531.jpg 

通過這種方式,我們的站點的搜索部分可以擁有更加友好的URL路徑(剩下的就是去實現檢索邏輯了,這部分作為留給讀者的練習)。

映射規則先決條件的驗證

前文中曾經提到Route類中含有一個Validation屬性,允許你設置匹配映射規則的先決條件。ASP.Net MVC框架允許你使用正則表達式驗證URL中的參數和分析HTTP Headers(根據不同的Verbs執行不同的映射規則)。

下面是一個可以用於類似於”/Products/Detail/43”的路徑的驗證規則。他指明了ID參數必須是一個數字(不允許字符出現),同時該參數必須是1-8個字符長:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130555.jpg

如果我們對應用程序發出/Products/Detail/12的請求,符合上面的映射規則,如果我們傳入/Products/Detail/abc,或者/Products/Detail/23232323232,則不符合該規則。

從映射系統中構造URL

前面提到了ASP.Net MVC框架的映射系統(Routing System)負責兩項任務:

  1. 將傳入的URL請求交由相應的控制類、操作方法進行處理
  2. 構建可以用於定位到控制類、操作方法的URL路徑(例如:form posts, <a href=””>鏈接,AJax調用等)

URL映射系統提供哦你了一些輔助方法和類,使得在運行時可以動態查找和構建URL(你也可以通過直接操作RouteTable的內容進行查找)。

Html.ActionLink

在Part 1中我曾經提到Html.ActionLink()視圖輔助方法。它可以用在視圖中動態產生<a href=””>鏈接。而且它可以根據映射系統中定義的URL映射規則產生URL,例如下面的兩個HtmlActionLink調用:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130636.jpg

該方法自動選擇我們在前邊定義的對應的Search結果映射規則,並將href屬性自動設置為:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130663.jpg

需要注意的是上面對Html.ActionLink的第二個調用自動將“page”參數作為URL的一部分(同時注意第一個調用略去了該參數,因為服務器端將會提供一個默認值)。

Url.Action

除了Html.ActionLink以外,ASP.Net MVC還提供了Url.Action()視圖輔助方法,該方法可以產生你希望使用的任何原始字符串URL,看一下下面的代碼:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130694.jpg

該方法根據URL映射系統返回下面的原始 URL(沒有用<a href=””>元素包裝):

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130630.jpg

Controller.RedirectToAction

ASP.Net MVC同樣支持在控制類中使用Controller.RedirectToActioin()輔助方法實現重定位(其中URL根據映射系統產生)。

例如下面在控制類中的調用代碼:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130676.jpg 

該方法在內部產生了一個到Response.Redirect(“/Search/Beverages”)的調用。

DRY

上面提到的輔助方法都有共同的優點就是避免我們把URL路徑因編碼到控制類和視圖邏輯中,因此如果以後我們想把檢索路徑的URL映射規則從“/Search/[query]/[page]”改回“/Search/Results/[query]/[page]或 /Search/Results?query=[query]&page=[page]”我們只需要在映射規則注冊的地方進行修改。我們不需要修改任何存在於控制類和視圖中的方法來定位到新的URL(這符合了“DRY法則”)

根據映射系統產生URL路徑(使用Lambda表達式)

前面的URL輔助方法展示了在C#和VB在VS2008中支持的anonymous type類型的優勢,在上面的例子中,我們通過使用anonymous type傳入一系列name/value以輔助產生URL(你可以把它當成一種產生詞典的快捷方式)

除了通過使用anonymous類型動態傳遞參數,ASP.Net MVC框架同樣支持通過使用可以提供編譯時檢查的強類型機制創建操作方法映射,該功能通過泛型和VB,C#對Lambda表達式的支持實現。

例如,下面的anonymous類型ActionLink調用:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130716.jpg

也可以被寫作:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130796.jpg

第二種方式除了書寫更加鑒別,同時具備類型安全的優點,這意味著你可在開發時可以得到Visual Studio提供的智能感知和編譯時錯誤檢查支持(你也可以針對它是喲哦那個映射工具):

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130731.jpg

注意上面我們可以使用智能感知功能取得SearchController類的Action()方法的,同時參數也都是強類型的,產生的URL路徑是受映射系統驅動的。

你或許想知道,這些是如何實現的,如果你仍然記得8個月前我寫的關於Lambda表達式的文章,該文章中提到Lambda表達式既可以編譯成為代碼委托,也可以作為運行時分析Lambda表達式的an expression tree object。通過Html.ActionLink<T>輔助方法,我們可以使用expression tree選項並在運行時分析lambda表達式並查找表達式中指定的參數類型,名稱和值。我們可以在URL映射系統中使用它產生相應的URL和相應的Html。

重要:當使用Lambda表達式時,我們並沒有真正的執行Controller的方法,例如:下面的代碼並沒有調用SearchController中的”Results”方法:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130796.jpg

相反它直接生成了Html鏈接:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130709.jpg

當用戶點擊這個鏈接時,它將產生一個調用SearchController的Results方法的請求。

單元測試映射

ASP.net MVC框架的核心設計規范對測試提供了良好的支持,例如你可以輕松的對映射規則進行單元測試。MVC映射系統可以被實例化並獨立於ASP.Net而運行,這意味著你可以使用任何單元測試庫(例如Nunit, MBUnit, MSTest等)加載映射模塊並進行測試。

盡管你可以直接對ASP.Net MVC應用的程序的全局映射表進行單元測試,然而一般來講讓單元測試依賴於全局狀態變量並不是一個好主意。而另一種你可以使用的更好的方式是將你的映射規則注冊邏輯封裝到一個RegisterRoutes()輔助方法中,像下面的代碼作為參數傳入的RouteCollection(在以後的版本中我們可能會把這種方式作為Vs的默認模式)。

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130859.jpg

這樣你就可以編寫單元測試創建獨立的RouteCollection實例並調用應用程序的類的RegisterRoutes()方法將映射規則注冊到應用程序中。你可以模擬各種請求並驗證是否返回了正確的控制類和操作方法,而不必擔心其他影響:

https://www.aspphp.online/bianchen/UploadFiles_4619/201701/2017011311130897.jpg

總結

希望這篇文章對ASP.net MVC的映射機制的工作原理以及在ASP.Net MVC應用程序中設計URL的結構有了更加深入的了解。

當你創建ASP.Net MVC Web程序時,一條默認的映射規則/[controller]/[action]/[id]被自動注冊(不需要你進行任何手動配置),這已經足夠你開發很多應用。但是希望這篇文章已經向你演示了如何簡單的自定義URL規則,以及MVC框架在這方面提供的強大功能和靈活性。

希望對你有所幫助,

Scott

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved