asp.net core 系列 5 MVC框架路由(上)

一. 概述

  介紹asp.net core路由時,我初步想了下,分幾篇來講明。  路由的知識點不少,參考了官方文檔提取出一些重要的知識點來講。    在ASP.NET Core中是使用路由中間件來匹配傳入請求的 URL 並將它們映射到操做(action方法)。路由是在程序啓動時進行傳統路由或屬性路由定義。 路由描述如何將 URL 路徑與操做相匹配。 它還用於在響應中生成送出的 URL(用於連接)。web

  路由操做既支持傳統路由,也支持屬性路由。也可混合使用。一般傳統路由用於爲瀏覽器處理 HTML 頁面的控制器。屬性路由用於處理 web API 的控制器。

api

  1.1設置路由中間件

要使用傳統路由,必須在UseMVC中間件中配置實現IRouteBuilder接口,在asp.net core mvc 2.2 框架下,應用程序Startup的Configure 方法中,默認路由設置以下:瀏覽器

app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });

在對 UseMvc調用中,MapRoute 用於建立單個路由,亦稱 default 路由。 大多數 MVC 應用使用帶有模板的路由。對於default路由簡便的方法能夠使用:mvc

app.UseMvcWithDefaultRoute();

  

    UseMvc 和 UseMvcWithDefaultRoute 可向中間件管道添加 RouterMiddleware 的實例。 MVC 不直接與中間件交互,而是使用路由來處理請求。 MVC 經過 MvcRouteHandler 實例鏈接到路由。

    UseMvc 不直接定義任何路由,它向屬性路由的路由集合添加佔位符{controller=Home}/{action=Index}/{id?} 。經過重載 UseMvc(Action<IRouteBuilder>) 則容許用戶添加本身的路由,而且還支持屬性路由。

  

 1.2 傳統路由

 傳統路由是:具備描述性的路由方案,這樣URL具備可讀性。傳統路由格式:{controller=Home}/{action=Index}/{id?}這樣的url路徑是設定了一個約定: 第一段映射到控制器名稱, 第二段映射到操做名稱,第二段映射到可選ID。app

 

 (1) 使用默認路由:  框架

routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");

使用此默認路由時: url路徑/Products/List 將映射到程序ProductsController(控制器).List(action)中。 url路徑/Blog/Article/17將映射到程序BlogController(控制器).Article(action)中。asp.net

 (2) 多個路由:ide

經過添加對 MapRoute 的屢次調用,能夠在 UseMvc 內添加多個路由。 這樣作能夠定義多個約定,或添加專用於特定操做的傳統路由,好比:post

app.UseMvc(routes =>
    {
     routes.MapRoute("blog", "blog/{*article}",
            defaults: new { controller = "Blog", action = "Article" });
     routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
   });

  這裏的blog路由是一個專用的傳統路由,這表示blog使用傳統路由系統,但專用於特定的操做,也就是對於BlogController控制器的Article操做,此專用路由將始終映射。對於多個路由的路由集合會進行排序,並按添加順序進行處理,所以,在此示例中,將先嚐試 blog 路由,再嘗試 default 路由。ui

 (3)  action操做的區分

 在處理url請求時,當經過路由匹配到一個控制器內兩項相同的action名稱時,mvc必須進行區分,以選擇最佳候選項,不然會引起異常(AmbiguousActionException)。

public class ProductsController : Controller
     {
       public IActionResult Edit(int id) { ... }

       [HttpPost]
       public IActionResult Edit(int id, Product product) { ... }
     }

此Products控制器定義了二項操做,這兩項操做均與 URL 路徑的 /Products/Edit/17 匹配相同。解決方案是將要提交的action加上 Http 謂詞爲 POST。這樣post過來時,就會選擇Edit(int, Product)

  1.3 屬性路由

    經過在控制器(Controller)或操做(Action)上放置路由可實現屬性路由。 不能經過傳統路由訪問定義屬性路由的操做,反之亦然。 控制器上的任何路由屬性,都會使控制器中的全部操做使用屬性路由。

    屬性路由使用一組屬性將action直接映射到路由模板。在下面的示例中,Configure 方法使用 app.UseMvc();,不傳遞任何路由。 HomeController 將匹配一組 URL,這組 URL 與默認路由 {controller=Home}/{action=Index}/{id?} 匹配的 URL 相似:

    當去掉default默認路由模板後,只使用app.UseMvc()時。運行程序時,頁面報404錯誤:找不到 localhost 的網頁。

 app.UseMvc();

    (1) 屬性路由基本使用   

    若是定義了屬性路由的操做,此時就是啓動屬性路由功能。Home控制器的屬性路由示例以下:

public class HomeController : Controller
    {
       [Route("")]
       [Route("Home")]
       [Route("Home/Index")]
       public IActionResult Index()
       {
          return View();
       }
    }

    在index的action上加[Route("")]屬性路由。 瀏覽器能夠使用下面三種url來訪問,也是程序啓動時的默認加載頁面:

      http://localhost:30081/

      http://localhost:30081/Home/

      http://localhost:30081/Home/index

(2) 屬性路由精確控制

屬性路由須要更多輸入來指定路由;傳統的默認路由處理路由的方式則更簡潔。 可是,屬性路由容許(並須要)精確控制應用於每項操做的路由模板。下面示例是精確控制每項操做的路由模板,好比url訪問/home/index時,便是調用MyIndex的action方法。

public class MyDemoController : Controller
    {
       [Route("")]
       [Route("Home")]
       [Route("Home/Index")]
       public IActionResult MyIndex()
       {
          return View("Index");
       }
    }
 1.4 使用 Http[Verb] 屬性的屬性路由

屬性路由還能夠使用 Http[Verb] 屬性,好比 HttpPostAttribute 全部這些屬性均可採用路由模板。 此示例展現,同一路由模板匹配的兩項操做:

[HttpGet("/products")]
    public IActionResult ListProducts()
    {
       // ...
    }

    [HttpPost("/products")]
    public IActionResult CreateProduct(...)
    {
       // ...
    }

    當 Http 謂詞爲 GET 時將執行ProductsApi.ListProducts 操做, 當 Http 謂詞爲 POST 時將執行 ProductsApi.CreateProduct。生成 REST API 時,不多會在操做方法上使用 [Route(...)]。 建議使用更特定的 Http*Verb*Attributes 來明確 API 所支持的操做。 REST API 的客戶端須要知道映射到特定邏輯操做的路徑和 Http 謂詞。

    例以下面一個web api訪問路由,使用Http*Verb*Attributes 來明肯定義以下:

 public class ProductsApiController : Controller
    {
       [HttpGet("/products/{id}", Name = "Products_List")]
       public IActionResult GetProduct(int id) { ... }
    }

  上面定義只有針對如訪問url如: /products/3(而非 /products)之類的 URL纔會執行 ProductsApi.GetProduct(int) 操做。

 1.5 路由合併

    若要使屬性路由減小重複,可將控制器Controller上的路由屬性與各個操做Action上的路由屬性合併。 控制器上定義的全部路由模板均做爲操做上路由模板的前綴。 在控制器上放置路由屬性會使控制器中的全部操做都使用屬性路由。

    下面是一個web api的路由合併,訪問Get的方法的訪問路徑爲: http://localhost:30081/api/Products/1

[Route("api/Products")]
    public class ProductsApiController : Controller
    {
        // GET api/values/5
        [HttpGet("{id}")]
        public string Get(int id)
        {
            return "value";
        }
    }

下面是一個控制器的路由合併。訪問index頁面的訪問路徑爲: http://localhost:30081/home/index

[Route("Home")]
  public class HomeController : Controller
  {
    [Route("")]      // Combines to define the route template "Home"
    [Route("Index")] // Combines to define the route template "Home/Index"
    [Route("/")]     // Doesn't combine, defines the route template ""
    public IActionResult Index()
    {
      //...
    }
  }
 1.6 指定屬性路由參數約束
  [HttpGet("Home/{id:int}",Name = "Pri")]
        public IActionResult Privacy(int id)
        {
            return View();
        }

若是輸入非整數類型的參數,瀏覽器提示:找不到與如下網址對應的網頁:http://localhost:30081/home/dd

   1.7 自定義路由屬性

    該框架中提供的全部路由屬性([Route(...)]、[HttpGet(...)] 等)均可實現 IRouteTemplateProvider接口。 當應用啓動時,MVC 會查找控制器類和操做方法上的屬性,並使用可實現 IRouteTemplateProvider的屬性生成一組初始路由。

    下面使用IRouteTemplateProvider 來定義本身的路由屬性。每一個 IRouteTemplateProvider 都容許定義一個包含自定義路由模板、順序和名稱的路由:

public class MyApiControllerAttribute : Attribute, IRouteTemplateProvider
    {
        //實現接口的三個屬性,這裏的[controller]是一個標記替換。
        public string Template => "api/[controller]/{action}/{id?}";

        public int? Order { get; set; }

        public string Name { get; set; }
    }    

    public class ProductsApiController : Controller
    {
        // GET api/values/5
        //  [HttpGet("{id}")]
        [MyApiController()]
        public string Get(int id)
        {
            return "value";
        }
    }

經過訪問url: http://localhost:30081/api/ProductsApi/get/1 來調用get方法。

參考文獻

  官方資料:asp.net core routing

相關文章
相關標籤/搜索