第二十節:Asp.Net Core MVC和WebApi路由規則的總結和對比


一. Core Mvc

1.傳統路由

  Core MVC中,默認會在 Startup類→Configure方法→UseMvc方法中,會有默認路由:routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}"); 等價於 app.UseMvcWithDefaultRoute();

(1). 參數解析說明

  name代表:路由名稱, template代表:路由模板,可以在上面直接賦默認值,defaults代表:路由默認值;constraints代表:路由約束

(2). 多個路由

  多個路由默認從上往下解析,注意路由名稱不能相同。

  比如: template: "{controller}/{action}/{id?}", 和 template: "{action}/{controller}/{id?}"兩個路由規則共存,那么我既可以通過 https://localhost:44333/Index2/Home 訪問頁面,也可以通過 https://localhost:44333/Home/Index2 訪問頁面

 1                 //1.默認路由
 2                 //1.1 簡版路由
 3                 {
 4                     routes.MapRoute("default", "{controller=Home}/{action=Index}/{id?}");
 5                 }
 6 
 7                 //1.2 路由名稱和多個參數的問題
 8                 {
 9                     routes.MapRoute(
10                                     name: "default",
11                                      template: "{controller}/{action}/{id?}",
12                                     defaults: new { controller = "Home", action = "Index" }
13                                     );
14                     routes.MapRoute(
15                                    name: "default2",
16                                    template: "{action}/{controller}/{id?}",
17                                    defaults: new { controller = "Home", action = "Index2" }
18                                    );
19                 }

2. 屬性路由

(1).Route[]

  Route可以單獨作用Controller,也可以單獨作用於action,當然也可以同時作用。

 (前提:注釋掉全局的傳統路由,當然也可以不注釋,因為同時存在的話,屬性路由的優先級高)

測試1:只在控制器上添加 [Route("Home2/{action}")],則可以通過【https://localhost:44333/Home2/Test1】正常訪問.

測試2:只在Test1方法上添加 [Route("{controller}/Test111")], 則可以通過【https://localhost:44333/Home/Test111】正常訪問

標記替換:直接以這種形式[Route("api/[controller]/[action]")]作用於控制器,該控制的匹配規則都將自動適配名稱,該方法普遍用於WebApi上.

代碼如下:

 1     [Route("Home2/{action}")]
 2     public class HomeController : Controller
 3     {
 4 
 5         [Route("{controller}/Test111")]
 6         public string Test1()
 7         {
 8             return "ok1";
 9         }
10     }

(2).Http[Verb]

  Http[Verb]只能單獨作用於action.

測試1:只在Test2方法上添加 [HttpGet("{controller}/Test22")],則可以通過【https://localhost:44333/Home/Test22】正常訪問

測試2:只在Test2方法上添加 [HttpGet("{controller}/Test22")]和[HttpGet("{controller}/Test222")],則可以通過【https://localhost:44333/Home/Test22】 和【https://localhost:44333/Home/Test232】正常訪問

代碼如下:

 1 public class HomeController : Controller
 2     {
 3         [HttpGet("{controller}/Test22")]
 4         [HttpGet("{controller}/Test222")]
 5         public string Test2()
 6         {
 7             return "ok2";
 8         }
 9 
10     }

(3).多個屬性路由的合並規則

A. Route和Route合並:Route可以同時作用在Controller和action,匹配規則是“疊加”;而且每個上面可以放多個,比如控制器上2個,action上3個,則有2*3=6種組合。

測試:控制器上添加:[Route("Home1/{action}")] 和 [Route("Home2/{action}")],

      action上添加:[Route("Test3")]、 [Route("Test33")]、 [Route("Test333")]

可以訪問路徑:https://localhost:44333/Home1/Test3/Test3

  https://localhost:44333/Home1/Test3/Test33

  https://localhost:44333/Home1/Test3/Test333 (訪問不了,因為action上Route以/開頭)

  https://localhost:44333/Home2/Test3/Test3

  https://localhost:44333/Home2/Test3/Test33

  https://localhost:44333/Home2/Test3/Test333 (訪問不了,因為action上Route以/開頭)

注:action上的屬性路由以 / 或 ~/ 開頭的路由模板不與應用於控制器的路由模板合並。

代碼如下:

 1     [Route("Home1/{action}")]
 2     [Route("Home2/{action}")]
 3     public class HomeController : Controller
 4     {
 5         [Route("Test3")]
 6         [Route("Test33")]
 7         [Route("/Test333")]
 8         public string Test3()
 9         {
10             return "ok3";
11         }
12 
13     }

B. Route和Http[Verb]合並,匹配規則也是“疊加”,而且每個上面可以放多個,比如控制器上2個,action上3個,則有2*3=6種組合。

 測試:控制器上添加:[Route("Home1/{action}")] 和 [Route("Home2/{action}")],

            action上添加:[HttpGet("Test3")]、 [HttpGet("Test33")]、 [HttpGet("Test333")]

可以訪問的路徑和上面的一樣,這里不再做重復測試了。

 

(4).擴展自定義屬性路由

  新建類,實現IRouteTemplateProvider接口,繼承Attribute類,然后就通過Template字段來聲明自定義屬性的路由規則了,如ypfAttribute類。

 1      /// <summary>
 2     /// 自定義路由特性
 3     /// </summary>
 4     public class ypfAttribute : Attribute, IRouteTemplateProvider
 5     {
 6         public string Template => "api/[controller]/[action]";
 7 
 8         /// <summary>
 9         /// 屬性排序
10         /// </summary>
11         public int? Order { get; set; }
12 
13         /// <summary>
14         /// 屬性名
15         /// </summary>
16         public string Name { get; set; }
17     

3.傳統路由和屬性路由共存

  通常情況下傳統路由服務於Core MVC,屬性路由服務於Restful Api,但如果二者共存的時候,屬性路由的優先級更高,傳統路由失效。

 測試案例:打開傳統路由【1.1】簡版路由,然后在Index方法加[Route("kkk")], 這個時候

  (1).要想訪問Index2頁面,走的依舊是傳統路由:https://localhost:44333/Home/Index2

  (2).要想訪問Index頁面,只能走屬性路由:https://localhost:44333/kkk

注:這里是把特性加在Index方法上,所以請求地址中不能有控制器名稱哦

 代碼如下:

 

4.區域路由(Area)

前提:必須給區域下的控制器加上特性標注區域名稱!!!如: [Area("A1_Areas")]

方案一:

  有幾個區域,則通過MapAreaRoute來添加幾個路由,放在傳統默認路由的前面。

 1         //3.1 有幾個區域配置幾個區域路由,並且放在默認路由的前面
 2                 {
 3                     //區域路由
 4                     routes.MapAreaRoute("myAreaRoute1", "A1_Areas", "{area}/{controller}/{action}/{id?}");
 5                     routes.MapAreaRoute("myAreaRoute2", "A2_Areas", "{area}/{controller}/{action}/{id?}");
 6 
 7                     //默認路由
 8                     routes.MapRoute(
 9                         name: "default",
10                         template: "{controller=Home}/{action=Index}/{id?}");
11 
12                 }

方案二:(推薦!)

  利用MapRoute方法,添加一個含{area:exists}的路由,必須放在默認路由的后面!

 1                 //3.2 單獨配置一個含area的路由,放在默認路由的后面
 2                 {
 3 
 4                     //默認路由
 5                     routes.MapRoute(
 6                         name: "default",
 7                         template: "{controller=Home}/{action=Index}/{id?}");
 8 
 9                     //區域路由(要放在默認路由的后面)
10                     routes.MapRoute(
11                       name: "default2",
12                       template: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
13                 }

測試:

  訪問Home/Index 頁面(上面什么特性不要加),里面的連接可以分別跳轉到A1和A2區域下的頁面。

 

二. Core WebApi

  默認情況下WebApi的路由規則是RestFul風格的,而且WebApi項目並沒有全局注冊傳統路由,這種模式很不友好.通常我們有兩類改造方案。

(前提補充:[Route]和[ApiController]要成對出現,可以同時和傳統路由共存,優先級比傳統路由高,但是[ApiController]不能單獨出現,不能單獨和傳統路由共存;而 [Route]可以單獨和全局路由共存)

方案一:全局配置,全局進行改造,在Configure方法中添加規則為:"api/{controller}/{action}/{id?}"和"api/{area:exists}/{controller}/{action}/{id?}"的全局路由和區域路由,則我們就可以通過上述路徑進行訪問了。

Core2.x版本

 1          app.UseMvc(routes =>
 2             {
 3                 //全局路由
 4                 routes.MapRoute(
 5                    name: "default",
 6                    template: "api/{controller}/{action}/{id?}",
 7                    defaults: new { controller = "Second", action = "Test" });
 8 
 9                 //區域路由(對應區域下面的控制器一定要加 [Area("")])
10                 routes.MapRoute(
11                   name: "default2",
12                   template: "api/{area:exists}/{controller}/{action}/{id?}");
13 
14 
15                 //用於顯示默認訪問,這樣直接打開https://localhost:44387/,就可以直接調用方法了。
16                 //routes.MapRoute(
17                 // name: "default3",
18                 // template: "{controller}/{action}/{id?}",
19                 // defaults: new { controller = "Second", action = "Test" });
20             });

Core3.x寫法

 1   app.UseEndpoints(endpoints =>
 2             {
 3                 //默認路由
 4                 endpoints.MapControllerRoute(
 5                     name: "default",
 6                 pattern: "{controller=Admin}/{action=LoginIndex}/{id?}");
 7                 //pattern: "{controller=Demo}/{action=Index}/{id?}");
 8 
 9                 //區域路由(要放在默認路由的后面)
10                 //注:必須以特性的形式在對應控制器上加上區域名稱 [Area("XXXX")]
11                 endpoints.MapControllerRoute(
12                    name: "default2",
13                    pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
14             });

方案二:不需要全局配置,在每個控制器的上面添加 [Route("api/[controller]/[action]")]和[ApiController],也可以達到同樣的目的。

 1     [Route("api/[controller]/[action]")]
 2     [ApiController]
 3     public class SecondController : ControllerBase
 4     {   
 5         [HttpGet]
 6         public string Test()
 7         {
 8             return "ok";
 9         }
10         [HttpGet]
11         public string Test2()
12         {
13             return "ok2";
14         }
15         [HttpPost]
16         public string Test3(UserInfor model)
17         {
18             return $"{model.userName}+{model.pwd}";
19         }
20     }

PS:在實際開發中,可以這兩種方案相互結合進行使用。

 

 

 

!

  • 作       者 : Yaopengfei(姚鵬飛)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 聲     明1 : 本人才疏學淺,用郭德綱的話說“我是一個小學生”,如有錯誤,歡迎討論,請勿謾罵^_^。
  • 聲     明2 : 原創博客請在轉載時保留原文鏈接或在文章開頭加上本人博客地址,否則保留追究法律責任的權利。
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM