摘要:ASP.NET MVC 原始程式碼更新預覽
【原文位址】ASP.NET MVC Source Refresh Preview
【原文發表日期】 Wednesday, April 16, 2008 9:56 PM
最近我們開啟了一個新的ASP.NET CodePlex 專案,我們將用它來提供將要發佈的ASP.NET特性的預覽(以及可編譯的程式碼)。
上個月,我們用它發佈了ASP.NET MVC原始程式碼的第一個投放,這個投放包括了我們在MIX上發佈的ASP.NET MVC第二個預覽版的原始程式碼,以及允許你修補和編譯的Visual Studio專案檔案。
幾小時前,我們在該網站上發佈了ASP.NET MVC原始程式碼的一個更新版。這個原始程式碼更新版 不是正式的ASP.NET MVC新的預覽版,而是一個過渡性的版本,旨在對原始程式碼樹的當前狀態提供一個樣本。我們將在幾個星期內完成一些工作後發佈正式的「ASP.NET MVC第三個預覽版」,這些工作包括新的特性以及對現有的特性的加工,更好的VS工具整合,VS Express版本的支援,以及檔案等。如果你想要一個毫無麻煩的ASP.NET MVC安裝版,帶有檔案以及完整的工具支援的話,你也許要等到這個正式的預覽版出來後再說。如果你想要有機會看一下早期的「預覽版的預覽」,馬上有機會開始使用一些特性,並且對它們提供回饋的話,那麼今天的原始程式碼更新版值得一看。
這個ASP.NET MVC原始程式碼更新版中的一些改進
這個星期的更新版(你可以在這裡下載)包括了對ASP.NET MVC的若干改進。這些改進包括:
-
除了發佈ASP.NET MVC框架的原始程式碼外,我們還發佈了我們用來測試該框架的單元測試的原始程式碼,這些測試是使用MSTest以及開源的Moq mocking 框架實現的。內含一個單元測試的VS 2008專案檔案,方便你在本地的VS 2008 IDE中編譯和執行。
-
對測試Controller類別顯著簡化了的支援,你現在可以不用mock任何對象就可以單元測試常見的Controller場景(詳情見下文)。
-
URL路徑選擇系統的幾個新特性和可用性方面的改進(詳情見下文)。
建立新的ASP.NET MVC專案
在下載MVC原始程式碼,在本地編譯後,你可以建造你自己的ASP.NET MVC程式集,或者你也可以下載一個VS模板套件,得到這些程式集的預製版本,其中包括一個 Visual Studio的專案模板,你可以用它來快速建造使用了最新程式碼的新ASP.NET MVC專案。
在安裝ASP.NET MVC原始程式碼更新 .VSI 模板後,一個新的「ASP.NET MVC應用」專案模板會出現在你的「新專案」對話框的「我的模板」部分:
這個新的「我的模板」版本的MVC專案模板可以與先前的ASP.NET MVC第二個預覽版並行存在,你可以在上面的對話框的主要專案模板部分看到。這允許你在同一個機器上安全地建立新專案,同時使用最新的原始程式碼版本和上個正式預覽版。
在你使用這個更新的ASP.NET MVC專案模板建立一個新專案時,在預設情形下,你將得到一個如下圖所示的專案:
這個專案方案在「\Controllers」目錄下包含一個Controller(「HomeController」),在「\Views\Home」子目錄下包含2個視圖模板(「About」和「Index」)。 2個視圖模板都基於網站的共同母版頁(「Site.master」),這些檔案的樣式定義於「\Content」目錄下的「Site.css」檔案中。
在你執行應用時,內建的web伺服器會自動啟動,你將看到網站的首頁內容:
點擊「About us」條,就會顯示「About」內容:
專案中的「HomeController」類別負責處理上面2個URL,有下述2個action方法:
預設的「Site.master」模板會在ViewData集合中尋找一個「Title」值,用它來顯示HTML頁面的<title>元素,預設的「Index」視圖模板會找一個「Message」,用它來顯示首頁的歡迎消息,很明顯,你可以進去客制這些檔案。
這個ASP.NET MVC投放版的Controller變動
如果你在認真閱讀上面的程式碼的話,你也許注意到了用這個新的ASP.NET MVC原始程式碼更新版預設實現的Controller類別中的幾個變動。
在ASP.NET MVC第二個預覽版中,上面的HomeController action方法是像這樣實現的:
MVC功能開發團隊在這個星期的投放版中正在試驗幾個想法,還在嘗試一些新的想法:
-
Controller中的Action方法現在預設傳回「ActionResult」物件(而不是void),這個ActionResult物件表示action方法的結果,如顯示一個視圖,重定向的URL,另一個要執行的action/路徑,等等。
-
Controller基類中的RenderView(),RedirectToAction(),和 Redirect() 輔助方法現在傳回強型別的ActionResult物件(你可以對其做進一步的操作或從action方法中傳回)。
-
RenderView()輔助方法現在可以不用顯式傳人要顯示的視圖模板名稱就可以叫用,如果你省略模板名字的話,在預設情形下,RenderView()方法將使用action方法的名字作為要顯示的視圖模板的名稱。所以,在「About()」 action方法中,不用參數叫用「RenderView()」現在跟顯式叫用「RenderView(『About』)」是一樣的。
很容易將用第二個預覽版建造的現有Controller類更新到使用這個新的模式(只要將void改成ActionResult,然後在任何RenderView或RedirectToAction方法叫用前加一個return語句就可以了。
從Action方法中傳回ActionResult物件
那麼,為什麼將Controller action方法改成預設傳回ActionResult,而不是傳回void呢?有幾個流行的Web-MVC框架使用同樣的傳回對象的方式(包括Django, Tapestry等),我們發現它給ASP.NET MVC帶來幾個好處:
-
它促成對Controller的更乾淨,更方便的單元測試支援。你不再需要對Response物件或ViewEngine對象的方法進行mock就可以單元測試action方法的回復行為,你只要簡單地在單元測試中使用從Action方法傳回的ActionResult進行assert就可以了(見下一部分)。
-
它可以在那些取決於某種條件會有2不同結果的場景中,使得Controller邏輯流的意圖更清晰,更明確(例如,如果條件A為真,就重新定向,否則顯示一個視圖模板)。這可以使得不簡單的控制器action方法的程式碼易讀,好懂些。
-
它能促成一些非常棒的組合場景,在這些場景中,FilterActionAttribute可以將action方法的結果,在執行之前進行修改、轉換。例如,ProductCatalog控制器的「Browse」方法也許會傳回一個RenderActionResult,表示它要顯示產品的「List」視圖,在控制器類上宣告的FilterActionAttribute然後就有機會取決於客戶端能接受的MIME型別,將要顯示的特定「List」視圖模板客制為List-html.aspx或List-xml.aspx。多個FilterA
ctionAttribute還可以鏈在一起,把結果從一個傳給另一個。 -
它還為開發人員(包括我們自己)提供了很好的擴展性機制,以在將來添加額外的功能。可以透過從ActionResult基類繼承,覆蓋其中的「ExecuteResult」方法來輕易地建立新的ActionResult 型別。例如,可以很輕易地建立一個「RenderFile()」輔助方法,編寫action方法的開發人員可以叫用它來傳回新的「FileActionResult」對象。
-
它在將來還將允許一些很棒的異步執行場景。Action方法可以傳回一個AsyncActionResult對象,表示它們在等待網路操作,想要放棄當前的工作執行緒,這樣ASP.NET可以用它來執行另一個請求,直到網路叫用結束為止。這會允許開發人員避免阻塞伺服器上的執行緒,支援非常有效和可擴縮的程式碼。
這個過渡性預覽版的一個目標是給大家一個機會把玩一下這個新方法,用它來建造現實的應用,從中學習一下。
我們還將發佈一個可為你所用的另外的Controller基類的樣例,如果你還是喜歡以前的「void」 action傳回值方式的話。但在這個原始程式碼更新版中,我們故意沒有包括這個另外的Controller基類,因為我們想要鼓勵大家嘗試一下「ActionResult」傳回方式,給我們一些用它來建造應用的回饋。
如何單元測試Controller Action方法
我在上面提到,新的ActionResult方法可以極大地簡化對控制器的單元測試,且避免在常見場景中使用mocking,讓我們透過一個實戰例子來示範一下。
考慮下面這個簡單的NumberController類別:
這個Controller類有一個「IsEvenNumber」 action方法,接受一個數字作為URL參數。IsEvenNumber action方法先檢查該數字是否是負數,如果是,就把用戶重新定向到出錯網頁。如果是正數的話,它會決定該數字是偶還是奇,然後叫用一個視圖模板來顯示適當的消息:
對我們的「IsEvenNumber」 action方法編寫單元測試非常容易,多虧新的ActionResult方法。
下面是一個單元測試例子,核實在提供負數時,正確的Http重新定向發生了(例如,/Number/IsEvenNumber/-1):
注意上面,我們不用mock任何對象就可以測試我們的action方法。我們只是生成了一個NumberController類的實例,直接叫用action方法(傳人一個負數),然後將傳回值賦給一個本地「result」變數。上面我用了C#的「as type」語法,將「result」變數轉換成一個強型別的「HttpRedirectResult」型別。
C#的 「as」 關鍵詞的一個好處是,如果轉換失敗的話,它會賦null值,而不是拋出異常(例如,如果action方法傳回的是個RenderViewResult)。這意味著,我可以輕鬆地在我的測試中加一個assertion檢查,核實結果不是null,以核實Http重新定向確實發生了。然後我可以加第二個assertion檢查,以核實指定了正確的重新定向URL。
測試非零數字的場景也很容易,要做的話,我們將建立2個測試方法,一個測試偶數,另一個測試奇數。在這2個測試中,我們將斷言傳回了RenderViewResult,然後核實在與視圖相關的ViewData中傳進了正確的「Message」字串:
然後我們可以在VS 2008中右擊我們的NumberControllerTest類,選擇「執行測試」選單項:
這會在記憶體中執行我們的三個單元測試(不需要web伺服器),報告我們的NumberController.IsEvenNumber() action方法是否執行了正確的行為:
註: 在這個星期的原始程式碼投放中,你還需要使用mocking來測試Controller的TempData屬性。我們的計劃是在幾個星期後的ASP.NET MVC第三個預覽版中不再需要mocking就可以測試這個屬性。
MapRoute輔助方法
ASP.NET MVC應用中的URL路徑選擇規則一般是在Global.asax類的「RegisterRoutes」方法中宣告的。
在ASP.NET MVC第一個預覽版和第二個預覽版中, 路徑是透過直接生成一個Route對象,將其連接到一個MvcRouteHandler類,然後設置其上的適當屬性來宣告路徑規則,再加到routes集合的:
上面的程式碼以後還會繼續工作,但是,你現在還可以利用新的「MapRoute」輔助方法,它提供了極其簡單的句法,但能做同樣的事。下面是在你建立一個新的ASP.NET MVC專案時,預設配置的基於約定的URL路徑(代替上面的程式碼):
MapRoute()輔助方法是重載了的,可以接受2,3,或4個參數(路徑名字,URL句法,URL預設參數,URL參數正則運算式約束)。
你可以叫用MapRoute()多次, 在系統中註冊多個具名的路徑。例如,除了預設的約定規則外,我們可以像下面一樣加一個名為「Products-Browse」的路徑規則:
然後我們可以在Controllers和Views中明確地引用這個「Products-Browse」規則,如果我們要生成一個針對它的URL的話。例如,我們可以在視圖模板中使用象下面這樣的程式碼,使用Html.RouteLink這個視圖輔助方法,來表示我們要連結到「Products-Browse」路徑上,同時給它傳一個「Food」分類參數:
這個視圖輔助方法然後就會訪問路徑選擇系統,輸出象下面這樣的適當的HTML超連結URL(注意它是如何自動地使用路徑規則將分類參數置換到URL中去的):
註: 在這個星期的原始程式碼投放中,你需要向Html.RouteLink()輔助方法中傳人控制器和action參數(除了分類參數外)來生成正確的路徑URL。幾個星期後的ASP.NET MVC第三個預覽版將不再要求這樣,而是允許你像我上面寫的Html.RouteLink叫用那樣,來確定路徑。
其他URL路徑映射功能
這個星期的MVC原始程式碼投放還支援一堆新的URL路徑映射功能,你現在可以在你的路徑規則中包含」-」, 「.」, 「;」 或任何其他你想要作為URL的一部分的字元。
例如,使用」-」 分割符你現在可以使用象下面這樣的規則從你的URL中分別分析出language和locale值:
這會叫用時,將合適的」language」, 「locale」, 和 「category」參數傳人ProductsController.Browse action方法中:
URL路徑規則 | URL例子 | 傳給Action方法的參數 |
{language}-{locale}/products/browse/{category} | /en-us/products/browse/food | language=en, locale=us, category=food |
/en-uk/produc ts/browse/food |
language=en, locale=uk, category=food |
或者你可以使用URL後面的 「.」 檔案擴展型別來決定是要以XML還是HTML格式來顯示內容:
這會在叫用時將」category」 和 「format」參數傳給ProductsController.Browse Action方法:
URL路徑規則 | URL例子 | 傳給Action方法的參數 |
products/browse/{category}.{format} | /products/browse/food.xml | category=food, format=xml |
/products/browse/food.html | category=food, format=html |
ASP.NET MVC第二個預覽版引進了萬用字元路徑規則,例如,你可以在一個規則中表示,把所有剩下的URI內容作為一個具名的參數傳給一個action方法:
這會在叫用時,將一個」contentUrl」 參數傳給WikiController.DisplayPage action方法:
URL路徑規則 | URL例子 | 傳給Action方法的參數 |
Wiki/Pages/{*contentUrl} | /Wiki/Pages/People/Scott | contentUrl=」People/Scott」 |
/Wiki/Pages/Countries/UK | contentUrl=」Countries/UK」 |
這些萬用字元路徑在本星期發佈的預覽更新版中還會照常工作,在你建造部落格,維基,CMS,或其他基於內容的系統時,這些規則非常值得一看。
注意,除了在ASP.NET MVC場景中使用新的路徑系統外,我們現在還將在ASP.NET動態資料(使用了ASP.NET Web Forms)中使用同樣的路徑系統。
結語
希望上面的內容對本星期的ASP.NET MVC原始程式碼更新版中的一些新功能和變動提供了簡短的說明。
你現在可以在這裡下載,如果你想要馬上開始使用它的話。或者,你也可以等上幾個星期,等正式的 ASP.NET MVC第三個預覽版發佈,這正式的版本將擁有更多的功能(也會融入大家對本星期的版本的回饋),提供更加無縫的安裝程式,提供很好的VS整合,提供更新的檔案。
對本星期的ASP.NET MVC更新版有什麼問題的話,一定要去www.asp.net上的ASP.NET MVC論壇詢問。
希望本文對你有所幫助,
Scott