Asp.net mvc 知多少(二)

weixin_33860722發表於2016-12-16

本系列主要翻譯自《ASP.NET MVC Interview Questions and Answers 》- By Shailendra Chauhan,想看英文原版的可訪問http://www.dotnettricks.com/free-ebooks自行下載。該書主要分為兩部分,ASP.NET MVC 5、ASP.NET WEB API2。本書最大的特點是以面試問答的形式進行展開。通讀此書,會幫助你對ASP.NET MVC有更深層次的理解。
由於個人技術水平和英文水平也是有限的,因此錯誤在所難免,希望大家多多留言指正。
系列導航
Asp.net mvc 知多少(一)
Asp.net mvc 知多少(二)
Asp.net mvc 知多少(三)
Asp.net mvc 知多少(四)
Asp.net mvc 知多少(五)
Asp.net mvc 知多少(六)
Asp.net mvc 知多少(七)
Asp.net mvc 知多少(八)
Asp.net mvc 知多少(九)
Asp.net mvc 知多少(十)

本節主要講解MVC的管道及路由機制


Q13. Asp.net mvc 中的ViewModel?
Ans. 在 ASP.NET MVC中, ViewModel 是一個包含將在強型別檢視中展示的欄位的類。它是用來將資料從Controller傳遞到強型別檢視中。
ViewModel的關鍵點:

  • ViewModel 包含在檢視中呈現的欄位。(LabelFor, EditorFor, DisplayFor helpers)
  • ViewModel 可以通過資料註解指定特定的驗證規則。
  • ViewModel 可以包含多個來自不同資料模型或資料來源的實體或物件。

Q14. 解釋下 ASP.NET MVC pipeline(管道)?
Ans. 先上圖:

2799767-990fcc7367daeffa.png
ASP.NET MVC pipeline
  1. Routing(路由) - 路由是管道的第一步。簡單來說,它是一種模式匹配系統,去路由表中註冊的Url中匹配傳入的請求。在程式碼中主要是UrlRoutingModule(System.Web.Routing.UrlRoutingModule)在做匹配的工作,路由表對應的是RouteTable(System.Web.Routing.RouteTable)

  2. Controller Initialization(初始化控制器) - MvcHandler使用ProcessRequest方法開始對ASP.NET MVC pipeline進行實時處理。這個方法使用工廠類IControllerFactory的例項(預設是System.Web.Mvc.DefaultControllerFactory)去建立對應的Controller。

  3. Action Execution (Action執行)– 該環節按以下順序執行:

  • 當Controller初始化後,Controller通過傳遞選擇的action方法詳情呼叫它自己的InvokeAction()方法。這一步是由IActionInvoker處理。

  • 當選擇合適的action方法後,model binder(模型繫結器,預設是System.Web.Mvc.DefaultModelBinder)取回傳入的Http請求的資料,然後進行資料轉換,資料驗證(比如required、資料格式等)。同時還需要將資料對映到action方法對應的引數上。

  • Authentication Filter (認證過濾器)是在ASP.NET MVC5中引入的,它先於authorization filter(授權過濾器)執行。它主要用來對使用者認證。認證過濾器處理請求中的使用者憑證並返回相應的主體。在ASP.NET MVC5之前,使用 authorization filter (授權過濾器)對使用者進行認證和授權。 Authenticate attribute(認證特性)預設是被用來進行認證. 可以通過實現IAuthenticationFilter介面來建立自定義的authentication filter(認證過濾器)

  • Authorization filter(授權過濾器)用來對已認證的使用者執行授權操作。例如。基於角色的授權。Authorize attribute(授權特性預設用來執行授權操作)。可以通過實現IAuthorizationFilter介面來建立自定義的authentication filter(授權過濾器)。

  • Action filters (Action過濾器)在 OnActionExecuting之前OnActionExecuting之後執行。IActionFilter介面提供了兩個方法 OnActionExecutingOnActionExecuting分別在action之前和之後執行。通過實現IActionFilter 該介面來自定義Action過濾器。

  • action執行後, 通過model(Business Model or Data Model)去處理使用者輸入並準備對應的Action Result。

4.Result Execution (返回執行結果階段)- 該階段主要包含以下步驟:

  • Result filters(結果過濾器) 在(OnResultExecuting)之前 (OnResultExecuted)之後執行。 IResultFilter 介面提供兩個方法 OnResultExecuting 、OnResultExecuted分別對應在ActionResult之前和之後執行。可以通過實現IResultFilter介面來自定義結果過濾器。
  • Action Result是BLL或者DAL對使用者輸入執行相應的操作後的返回結果。Action Result 的型別可以是 ViewResult, PartialViewResult, RedirectToRouteResult, RedirectResult, ContentResult,
    JsonResult, FileResult, EmptyResult。這些返回型別可以分為兩類,即ViewResult型別和 NonViewResult 型別。ViewResult 型別主要用於返回並渲染html頁面到瀏覽器。NonViewResult僅僅返回資料,比如文字、二進位制、json 格式資料。

4.1 View Initialization and Rendering (檢視初始化及渲染)- 可以分解為以下幾個步驟:

  • ViewResult 型別,比如 view、partial view 都是實現了 IView (System.Web.Mvc.IView) 介面並由相應的檢視引擎進行渲染。
  • 這一過程主要由檢視引擎的 IViewEngine (System.Web.Mvc.IViewEngine) 介面負責。預設ASP.NET MVC 提供了WebForm、Razor 兩種檢視引擎。可以通過實現 IViewEngine 建立自定義的檢視引擎並註冊自定義檢視引擎到ASP.NET MVC應用程式。
  • Html Helpers 主要用來建立html輸入控制元件,基於路由建立連結,建立ajax錶帶等等。Html Helpers 是 HtmlHelper的擴充套件類並可以很好的進行進一步擴充套件。 在複雜的情形中,可以渲染一個有前端驗證機制的JavaScript或jquery驗證。

Q15. 解釋下 ASP.NET MVC 的路由機制?
Ans. 路由是一種模式匹配系統,用來監視傳入的請求並決定如何處理請求。在執行時,路由引擎使用路由表去匹配傳入的請求的Url,根據路由表定義的Url格式與傳入的Url格式進行匹配。可以在Application_Start 事件中註冊一個或多個Url格式到路由表中。
當路由引擎在路由表中找到一個與傳入的Url請求匹配的路由記錄,路由引擎會轉發請求到對應的Controller、Action中。如果沒有匹配的記錄,則返回404。
大致處理流程如下圖:

2799767-a01a28d882ae4fd4.png
路由處理流程

Q16. 如何在ASP.NET MVC中定義路由?
Ans. 可以參照下面程式碼定義路由:

public static void RegisterRoutes(RouteCollection routes)
{
 routes.MapRoute(
 "Default", // Route name
 "{controller}/{action}/{id}", // Route Pattern
 new
 {
 controller = "Home",
 action = "Index",
 id = UrlParameter.Optional
 }// Default values for above defined parameters
 );
}
protected void Application_Start()
{
 RegisterRoutes(RouteTable.Routes);
 //TODO:
}

需要注意的是路由名稱必須是唯一命名不可重複。
在以上的例子中我們定義一個{controller}/{action}/{id} 這樣的路由併為Controller、Action、id引數提供了預設值。如果你的url中未包含某一項值,路由引擎會用定義的路由的預設值填充。
假設你的web應用程式掛載在 www.example.com,那麼你的url應該是www.example.com/{controller}/{action}/{id}這樣的。
下面是針對定義的路由的匹配結果:

2799767-6c0ecdf296ab6fa4.png
路由匹配結果

Note: 總是將特殊的路由定義在路由的最上邊。因為路由系統是從上往下對傳入的請求進行匹配,如果有一個匹配上,就不會繼續往下尋找路由進行匹配。

PS: 這裡推薦一個很實用的路由檢查外掛RouteDebugger,進行路由的分析。
使用方法很簡單:
1.在對應的mvc專案上通過Nuget包安裝RouteDebugger即可。
2.執行專案,就可以在網頁的下方,可以看到羅列的路由定義及匹配到的路由。效果如圖:

2799767-63288dd3275fc30e.png
RouteDebugger效果圖

3.可以通過web.config的AppSettings節點的<add key="RouteDebugger:Enabled" value="true" />進行禁用。


Q17. 什麼是特性路由,如何定義特性路由?
Ans. ASP.NET MVC5 、WEB API 2 支援的一種新路由的方式,叫做attribute routing(特性路由)。這種路由方式中,特性被用來定義路由,特性路由使我們能夠更好的控制URLs,支援直接在action和controller上定義路由。

  1. Controller level routing (控制器級別路由)– 可以為一個controller定義路由,那麼它所以的action都將應用此路由,除非一個特定的路由被直接定義在某一個action上。
[RoutePrefix("MyHome")]
[Route("{action=index}")] //default action
public class HomeController : Controller
{
 //new route: /MyHome/Index
 public ActionResult Index()
 {
 return View();
 }
 //new route: /MyHome/About
 public ActionResult About()
 {
 ViewBag.Message = "Your application description page.";
 return View();
 }
 //new route: /MyHome/Contact
 public ActionResult Contact()
 {
 ViewBag.Message = "Your contact page.";
 return View();
 }
}
  1. Action level routing (Action級別路由)– 可以通過在action上定義action級別路由,那麼這個action將被應用這個特定的路由。
public class HomeController : Controller
{
 [Route("users/{id:int:min(100)}")] //route: /users/100
 public ActionResult Index(int id)
 {
 //TO DO:
 return View();
 }
 [Route("users/about")] //route" /users/about
 public ActionResult About()
 {
 ViewBag.Message = "Your application description page.";
 return View();
 }
 //route: /Home/Contact
 public ActionResult Contact()
 {
 ViewBag.Message = "Your contact page.";
 return View();
 }
}

Note:

  • 特性路由應該在基於約定的路由之前配置。
  • 如果同時使用特性路由和基於約定的路由,若action上未定義特性路由,那麼action將按照基於約定的路由進行路由。在上面的示例中Contact()action將應用基於約定的路由,即/Home/Contact
  • 當僅僅定義了特性路由而沒有基於約定的路由時,若某個action未定義特性路由時,該action將不能被成功路由,會返回404。

Q18. 什麼時候使用特性路由?
Ans. 基於約定的路由一般用來支援確定的URI格式,常見於RESTful APIs。但是通過特性路由相對來說更加簡單的去定義URI格式。
例如,資源通常包含子資源,像客戶擁有訂單,電影有演員,書籍有作者等。通常會建立URIS去反應這種關係,類似/clients/1/orders
這種型別的URI用基於約定的路由是很難定義的。即使可以定義,如果有很多controllers、資源型別,那定義的路由也將差強人意。
使用特性路由,就會非常簡單定義此類路由,只需要在controller的action上新增一個attribute即可。

[Route("clients/{clientId}/orders")]
public IEnumerable<Order> GetOrdersByClient(int clientId)
{
 //TO DO
}

Q19. 如何啟用特性路由?
Ans. 通過在RouteConfig.cs檔案的RegisterRoutes()方法中新增routes.MapMvcAttributeRoutes()呼叫即可。

public class RouteConfig
{
 public static void RegisterRoutes(RouteCollection routes)
 {
 routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

 //enabling attribute routing
 routes.MapMvcAttributeRoutes();
 }
}

特性路由和基於約定的路由可以同時使用。

public class RouteConfig
{
 public static void RegisterRoutes(RouteCollection routes)
 {
 routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 //enabling attribute routing
 routes.MapMvcAttributeRoutes();
 //convention-based routing
 routes.MapRoute(
 name: "Default",
 url: "{controller}/{action}/{id}",
 defaults: new { controller = "Home", action = "Index", id =
UrlParameter.Optional });
 }
}


Q20. 如何在Area中定義特性路由?
Ans. 通過為Area中的Controller定義 RouteArea特性。當你為一個Area中的所有controller定義了特性路由,那就可以刪除為這個area註冊路由的AreaRegistration 類。

[RouteArea("Admin")]
[RoutePrefix("menu")]
[Route("{action}")]
public class MenuController : Controller
{
 // route: /admin/menu/login
 public ActionResult Login()
 {
 return View();
 }
 // route: /admin/menu/products
 [Route("products")]
 public ActionResult GetProducts()
{
 return View();
 }
 // route: /categories
 [Route("~/categories")]
 public ActionResult Categories()
 {
 return View();
 }
}

Q21. 路由與URL重寫的區別是什麼?
Ans. 路由和Url重寫都可以用來定義出SEO友好型的URLS。但是它們的實現方式是十分不同的,主要區別在:

  • URL rewriting(URL重寫)注重將一個URL對映到另一個URL。 而Routing(路由)注重將一個URL對映到一個資源。
  • URL rewriting(URL重寫)重寫你的舊的URL到一個新的URL。而Routing(路由)只是將URL對映到它對應的原始路由。

Q22. 什麼是 Route Constraints (路由約束)?
Ans. Route constraints(路由約束)是對已定義路由進行一些驗證的方式。假設我們已經定義了以下路由:

public static void RegisterRoutes(RouteCollection routes)
{
 routes.MapRoute(
 "Default", // Route name
 "{controller}/{action}/{id}", // Route Pattern
 new
 {
 controller = "Home",
 action = "Index",
 id = UrlParameter.Optional
 } // Default values for parameters
 );
}

當我們希望限制傳入請求的Url中的Id引數是數學型別的,可以採用以下方式:

public static void RegisterRoutes(RouteCollection routes)
{
 routes.MapRoute(
 "Default", // Route name
 "{controller}/{action}/{id}", // Route Pattern
 new
 {
 controller = "Home",
 action = "Index",
 id = UrlParameter.Optional
 }, // Default values for parameters
 new { id = @"\d+" } //Restriction for id(限制Id未數字型別)
 );
}

這樣對路由定義後,就限制瞭如果有第三個引數id,id必須為數字型別。只有類似http://example.com/Admin/Product/1這樣的Url才能成功路由。


Q23. 路由表是如何建立的?
Ans. 當Mvc應用程式第一次啟動時,global.asax類中的Application_Start() 方法呼叫RegisterRoutes()方法。RegisterRoutes()方法負責建立了路由表。

相關文章