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

相关文章
相关标签/搜索