自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

解讀ASP.NET 5 & MVC6系列(11):Routing路由

移動(dòng)開(kāi)發(fā) Android
在ASP.NET 5和MVC6中,Routing功能被全部重寫(xiě)了,雖然用法有些類(lèi)似,但和之前的Routing原理完全不太一樣了,該Routing框架不僅可以支持MVC和Web API,還支持一般的ASP.NET5程序。新版的改變有如下幾個(gè)部分。

 新版Routing功能介紹

在ASP.NET 5和MVC6中,Routing功能被全部重寫(xiě)了,雖然用法有些類(lèi)似,但和之前的Routing原理完全不太一樣了,該Routing框架不僅可以支持MVC和Web API,還支持一般的ASP.NET5程序。新版的改變有如下幾個(gè)部分。

首先,Routing系統(tǒng)是基于ASP.NET 5的,是一個(gè)獨(dú)立于MVC的路由框架,而不是基于MVC的。MVC只是在上面擴(kuò)展了一個(gè)快捷方式而已。

其次,在ASP.NET 5中,MVC和Web API控制器沒(méi)有區(qū)別了,即合二為一了。兩者派生于同一個(gè)Controller基類(lèi)。也就是說(shuō)該Routing框架是適用于兩者的,適用于MVC則意味著也適用于Web API。

***,不管在基于約定的Route聲明還是基于Attribute的Route聲明,都可以使用內(nèi)聯(lián)約束和參數(shù)選項(xiàng)。例如,你可以約定路由中某個(gè)參數(shù)的數(shù)據(jù)類(lèi)型,也可以讓一個(gè)參數(shù)標(biāo)記為可選類(lèi)型,再或者給其提供一個(gè)默認(rèn)值。

Routing框架的主要流程

基本的Routing框架是基于Middleware來(lái)實(shí)現(xiàn)的,這樣就可以將其添加到HTTP的請(qǐng)求Pipeline中了,它可以喝其它任意Middleware一起進(jìn)行組合使用,如靜態(tài)文件處理程序、錯(cuò)誤頁(yè)、或者SignalR服務(wù)器。

在使用Routing框架之前,首要要了解Routing的作用,作用很簡(jiǎn)單:

對(duì)于HTTP請(qǐng)求,Routing系統(tǒng)負(fù)責(zé)找出與之匹配的route,創(chuàng)建route數(shù)據(jù),并將該請(qǐng)求派送到該route對(duì)于的處理程序(Handler)上。

Controller和Action的選擇,只是MVC的Handler的一個(gè)具體實(shí)現(xiàn),該實(shí)現(xiàn)使用route數(shù)據(jù)和HTTP請(qǐng)求中的其它信息來(lái)選擇要執(zhí)行的Controller和Action。在新版的MVC6中,該處理程序的名稱為MvcRouteHandler。

路由系統(tǒng)的執(zhí)行流程如下

ASP.NET 5監(jiān)聽(tīng)到一個(gè)HTTP請(qǐng)求。然后Routing Middleware就會(huì)嘗試將route集合中的route匹配該請(qǐng)求。

一旦成功匹配一個(gè)請(qǐng)求,就找出該route對(duì)應(yīng)的handler。

調(diào)用該handler上的RouteAsync方法(因?yàn)樗械膆andler都要實(shí)現(xiàn)該接口方法)。

RoutingContext有一個(gè)IsHandled標(biāo)記,如果該標(biāo)記設(shè)置為true,則意味著該請(qǐng)求已經(jīng)被這個(gè)handler成功處理了;如果設(shè)置為false,則意味著該handler無(wú)法處理該請(qǐng)求,系統(tǒng)會(huì)再為此匹配一個(gè)route。

和之前的Routing系統(tǒng)有點(diǎn)不同的是,老版的Routing系統(tǒng)一旦成功匹配一個(gè)路由,就將其交由其對(duì)應(yīng)的Handler,不管對(duì)應(yīng)的Handler能不能處理該請(qǐng)求,所以就會(huì)出現(xiàn)route匹配成功了,但是找不到對(duì)應(yīng)的action,此時(shí)就會(huì)出現(xiàn)404錯(cuò)誤,而新版對(duì)此作出了上述第4步驟的改進(jìn)(重新將控制權(quán)交回給Routing系統(tǒng),進(jìn)行重新匹配),看起來(lái)還是非常不錯(cuò)的。

Route參數(shù)和約束條件的改進(jìn)

在之前的route設(shè)置中,要約束一個(gè)參數(shù)的數(shù)據(jù)類(lèi)型的話,我們需要使用類(lèi)型如下代碼:

  1. routes.MapRoute( 
  2.     "Product",  
  3.     "Product/{productId}",  
  4.     defaults: new { controller = "Product", action = "Details" }, 
  5.     constraints: new { productId = @"\d+" });

而在新版route中,就可以直接設(shè)置Product/{productId:int}了,約束條件遵守如下約定:

 

  1. {parameter:constraint} 

目前支持的約束如下:

解讀ASP.NET 5 & MVC6系列(11):Routing路由

 

而對(duì)于可選參數(shù),則值需要在約束類(lèi)型后面加一個(gè)問(wèn)號(hào)即可,示例如下:

  1. routes.MapRoute( 
  2.     "Product",  
  3.     "Product/{productId:long?}",  
  4.     new { controller = "Product", action = "Details" });

如果參數(shù)是必填的,需要保留一個(gè)默認(rèn)值的話,則可以按照如下示例進(jìn)行設(shè)置:

  1. routes.MapRoute( 
  2.     "Product",  
  3.     "Product/{productId:long=1000}"
  4.     new { controller = "Product", action = "Details" });

通用Routing

關(guān)于示例使用,我們先不從MVC開(kāi)始,而是先從普通的Routing使用方式開(kāi)始,新版route添加的時(shí)候默認(rèn)添加的是TemplateRoute實(shí)例,并且在該實(shí)例實(shí)例化的時(shí)候要設(shè)置一個(gè)Handler。

舉例來(lái)說(shuō),我們先創(chuàng)建一個(gè)空的ASP.NET 5項(xiàng)目,并在project.json文件的dependencies節(jié)點(diǎn)中添加程序集"Microsoft.AspNet.Routing": "1.0.0-beta3",,在Startup.cs的Configure方法里添加如下代碼:

  1. public void Configure(IApplicationBuilder app) 
  2.     RouteCollection routes = new RouteCollection(); 
  3.     routes.Add(new TemplateRoute(new DebuggerRouteHandler("RouteHandlerA"), ""null)); 
  4.     routes.Add(new TemplateRoute(new DebuggerRouteHandler("RouteHandlerB"), "test/{a}/{b:int}"null)); 
  5.     routes.Add(new TemplateRoute(new DebuggerRouteHandler("RouteHandlerC"), "test2"null)); 
  6.  
  7.     app.UseRouter(routes); // 開(kāi)啟Routing功能 
  8. }

在這里,我們?cè)O(shè)置HTTP請(qǐng)求處理的的Handler為DebuggerRouteHandler,該類(lèi)繼承于IRouter,實(shí)例代碼如下:

  1. public class DebuggerRouteHandler : IRouter 
  2.     private string _name; 
  3.  
  4.     public DebuggerRouteHandler(string name) 
  5.     { 
  6.         _name = name; 
  7.     } 
  8.  
  9.     public string GetVirtualPath(VirtualPathContext context) 
  10.     { 
  11.         throw new NotImplementedException(); 
  12.     } 
  13.  
  14.     public async Task RouteAsync(RouteContext context) 
  15.     { 
  16.         var routeValues = string.Join("", context.RouteData.Values); 
  17.         var message = String.Format("{0} Values={1} ", _name, routeValues); 
  18.         await context.HttpContext.Response.WriteAsync(message); 
  19.         context.IsHandled = true
  20.     } 

上述類(lèi),繼承IRouter以后,必須實(shí)現(xiàn)一個(gè)RouteAsync的方法,并且如果處理成功,則將IsHandled設(shè)置為true。

訪問(wèn)如下網(wǎng)址即可查看相應(yīng)的結(jié)果:

  1. 正常:`http://localhost:5000/` 
  2. 正常:`http://localhost:5000/test/yyy/12` 
  3. 404 :`http://localhost:5000/test/yyy/s` 
  4. 正常:`http://localhost:5000/test2` 
  5. 404 :`http://localhost:5000/test3`

注意:TemplateRoute和DebuggerRouteHandler都繼承于IRouter,是實(shí)現(xiàn)前面所述的不出現(xiàn)404錯(cuò)誤(繼續(xù)匹配下一個(gè)路由)的核心。

MVC中的Routing

在MVC示例程序中,我們只需要配置在調(diào)用app.UseMVC方法的時(shí)候,使用委托中的MapRoute方法來(lái)定義各種route就可以了。在這里我們以空白項(xiàng)目為例,來(lái)看看MVC的route如何使用。

***步:在project.json文件的dependencies節(jié)點(diǎn)中引用程序集"Microsoft.AspNet.Mvc": "6.0.0-beta3",

第二部:添加MVC的Middleware,并使用MVC,然后添加一條默認(rèn)的路由,代碼如下:

  1. public void ConfigureServices(IServiceCollection services) 
  2.     services.AddMvc(); 
  3.  
  4. public void Configure(IApplicationBuilder app) 
  5.     app.UseMvc(routeBuilder => 
  6.     { 
  7.         routeBuilder.MapRoute( 
  8.             name: "default"
  9.             template: "{controller}/{action}/{id?}"
  10.             defaults: new { controller = "Home", action = "Index" }); 
  11.     }); 
  12. }

第三步:分別創(chuàng)建如下如下三種Controller,其中ProductsController繼承于Microsoft.AspNet.Mvc下的Controlle

  1. public class ProductsController : Controller 
  2.     public IActionResult Index() 
  3.     { 
  4.         return Content("It Works with Controller Base Class!"); 
  5.     } 
  6.  
  7. public class DemoController 
  8.     public IActionResult Index() 
  9.     { 
  10.         return new ObjectResult("It Works without Controller Base Class!"); 
  11.     } 
  12.  
  13. public class APIController 
  14.     public object Index() 
  15.     { 
  16.         return new { Code = 100000, Data = "OK" }; 
  17.     } 

 

訪問(wèn)http://localhost:5000/products和http://localhost:5000/demo,均能顯示正常的輸出結(jié)果;而訪問(wèn)http://localhost:5000/api的時(shí)候返回的則是json數(shù)據(jù)。

這就是我們?cè)谇懊鍭SP.NET5新特性中所講的MVC和API合二為一了,并且也可以不繼承于Controller基類(lèi)(但類(lèi)名要以Controller結(jié)尾)。這種技術(shù)的核心是Controller的查找機(jī)制,關(guān)于如何在一個(gè)項(xiàng)目中查找合適的程序集,請(qǐng)參考《Controller與Action》章節(jié)。

新版MVC在判定Controller的時(shí)候,有2個(gè)條件:要么繼承于Controller,要么是引用MVC程序集并且類(lèi)名以Controller結(jié)尾。所以,在創(chuàng)建MVC Controller和Web API Controller的時(shí)候,如果你不需要相關(guān)的上下文(如HTTPContext、ActionContext等)的話,則可以不必繼承于Controller基類(lèi);但推薦都繼承于Controller,因?yàn)榭梢远喽嗬没?lèi)的方法和屬性,因?yàn)椴还芾^承不繼承,你定義的所有Controller類(lèi)都要走M(jìn)VC的各個(gè)生命周期,我們通過(guò)ActionFilter來(lái)驗(yàn)證一下:

***步:在project.json文件的dependencies節(jié)點(diǎn)中引用程序集"Microsoft.AspNet.Server.WebListener": "1.0.0-beta3"。

第二步:創(chuàng)建一個(gè)Aciton Filter,分別在Action執(zhí)行前和執(zhí)行后輸出一行文字,代碼如下:

  1. public class ActionFilterTest : IActionFilter 
  2.     public void OnActionExecuting(ActionExecutingContext context) 
  3.     { 
  4.         var typeName = context.Controller.GetType().FullName; 
  5.         Console.WriteLine(typeName + "." + context.ActionDescriptor.Name + ":Start"); 
  6.     } 
  7.  
  8.     public void OnActionExecuted(ActionExecutedContext context) 
  9.     { 
  10.         var typeName = context.Controller.GetType().FullName; 
  11.         Console.WriteLine(typeName + "." + context.ActionDescriptor.Name + ":END"); 
  12.     } 
  13.  
  14.   

 

第三步:在ConfigureServices方法里注冊(cè)該Action Filter

  1. services.Configure(options => {     options.Filters.Add(typeof(ActionFilterTest)); }); 

運(yùn)行程序,并訪問(wèn)響應(yīng)的路徑,三種類(lèi)型的代碼均會(huì)按計(jì)劃輸出內(nèi)容,輸出內(nèi)容如下:

  1. RouterTest.ProductsController.Index:Start 
  2. RouterTest.ProductsController.Index:End 
  3. RouterTest.DemoController.Index:Start 
  4. RouterTest.DemoController.Index:End 
  5. RouterTest.APIController.Index:Start 
  6. RouterTest.APIController.Index:End 

普通的ASP.NET5程序和MVC程序是可以在一起混合使用Routing功能的。

自定義Route

ASP.NET 5和MVC6都提供了豐富的Route自定義功能,關(guān)于普通Route的自定義,可以參考前面小節(jié)的DebuggerRouteHandler,這種方式需要實(shí)現(xiàn)自己的HTTP輸出,相當(dāng)于原來(lái)輕量級(jí)的IHttpHandler一樣。本節(jié),我們將這種在基于MVC的Route自定義功能,即定義的Route的Handler處理程序都是MvcRouteHandler。

在之前版本的MVC中,要自定義Route,一般都是繼承于RouteBase基類(lèi)或Route類(lèi);而在新版的MVC6中,要實(shí)現(xiàn)自定義Route,有三種方式,分別如下:

繼承于TemplateRoute

實(shí)現(xiàn)IRouter

實(shí)現(xiàn)INamedRouter(注:INamedRouter和IRouter的唯一區(qū)別是多了一個(gè)名稱)

本例中,我們以繼承繼承于TemplateRoute為例,首先創(chuàng)建一個(gè)繼承于該類(lèi)的子類(lèi)PromoTemplateRoute,該類(lèi)只匹配/promo目錄下的路徑

  1. public class PromoTemplateRoute : TemplateRoute 
  2.     public PromoTemplateRoute(IRouter target, string routeTemplate, IInlineConstraintResolver inlineConstraintResolver) 
  3.         : base(target, routeTemplate, inlineConstraintResolver: inlineConstraintResolver) 
  4.     { 
  5.     } 
  6.  
  7.     public PromoTemplateRoute(IRouter target, 
  8.                             string routeTemplate, 
  9.                             IDictionary

為了方便使用,我們也比葫蘆畫(huà)瓢,創(chuàng)建一些擴(kuò)展方法,示例如下:

public static class RouteBuilderExtensions
{
    public static IRouteBuilder MapPromoRoute(this IRouteBuilder routeCollectionBuilder, string name, string template)
    {
        MapPromoRoute(routeCollectionBuilder, name, template, defaults: null);
        return routeCollectionBuilder;
    }

    public static IRouteBuilder MapPromoRoute(this IRouteBuilder routeCollectionBuilder, string name, string template, object defaults)
    {
        return MapPromoRoute(routeCollectionBuilder, name, template, defaults, constraints: null, dataTokens: null);
    }

    public static IRouteBuilder MapPromoRoute(this IRouteBuilder routeCollectionBuilder, string name, string template, object defaults, object constraints, object dataTokens)
    {
        var inlineConstraintResolver = routeCollectionBuilder.ServiceProvider.GetService();         routeCollectionBuilder.Routes.Add(             new PromoTemplateRoute(                 routeCollectionBuilder.DefaultHandler,                 name,                 template,                 ObjectToDictionary(defaults),                 ObjectToDictionary(constraints),                 ObjectToDictionary(dataTokens),                 inlineConstraintResolver));          return routeCollectionBuilder;     }      private static IDictionary

使用的時(shí)候,則很簡(jiǎn)單,和之前的方式非常類(lèi)似,示例如下:

  1. routes.MapPromoRoute( 
  2.     name: "default2"
  3.     template: "promo/{controller}/{action}/{id?}"
  4.     defaults: new { controller = "Home", action = "Index" }); 

通過(guò)這種方式,我們可以在符合路由匹配條件的時(shí)候,使用PromoTemplateRoute類(lèi)來(lái)處理一些自定義邏輯,比如添加一些額外的文件頭信息等等。

基于Attribute的Routing

基于Attribute的Routing功能一直是MVC所期待的功能,在Web API已經(jīng)通過(guò)RoutePrefix(Controller上使用)和Route(Action上使用)來(lái)實(shí)現(xiàn)了。該特性在MVC 6中進(jìn)行了重寫(xiě)和增強(qiáng),并且由于MVC和Web API合二而一了,所以在這兩種Controller上都可以使用該特性。

舉例來(lái)說(shuō):

  1. [Route("bookhome")] 
  2. public class HomeController : Controller 
  3.     public IActionResult Index() 
  4.     { 
  5.         return View(); 
  6.     } 
  7.  
  8.     [Route("about")] 
  9.     public IActionResult About() 
  10.     { 
  11.         ViewBag.Message = "Your application description page."
  12.         return View(); 
  13.     } 
  14.  
  15.     [Route("contactus")] 
  16.     public IActionResult Contact() 
  17.     { 
  18.         ViewBag.Message = "Your contact page."
  19.         return View(); 
  20.     } 
  21. }

在上述Controller上定義一個(gè)bookhome前綴,并且在About和Contact上又分別定義了action名稱,所以上述3個(gè)Action的訪問(wèn)地址則是如下這種形式

  1. /bookhome 
  2. /bookhome/about 
  3. /bookhome/contactus 

在這里,我們需要注意,Controller和Action使用的Attribute都是Route,同時(shí),在這些路由模板字符串中,依然可以使用內(nèi)聯(lián)參數(shù),比如,我們可以定義類(lèi)似這樣的路由:

  1. [Route("products/{productId:int}")]

Controller和Action標(biāo)記位

另外,針對(duì)Route的模板字符串,不僅支持內(nèi)聯(lián)參數(shù),還支持Controller和Action的標(biāo)記位,即不用寫(xiě)死該Controller或Action的名稱,使用一個(gè)[controller]或[action]的字符即可表示該Controller或Action的名稱。比如,我們可以在Controller上定義這樣的一個(gè)路由(Action上什么都不定義):

  1. [Route("book/[controller]/[action]")] 

這樣訪問(wèn)首頁(yè)的地址就變成了:/book/Home/Index。

Web API的等價(jià)Route定義

在Web API中,我們一般還要定義GET、POST這樣的請(qǐng)求方式,為了方便,新版的HTTPGET等一系列方法都集成了Route功能,直接在構(gòu)造函數(shù)傳入Route模板即可,示例如下:

  1. [HttpGet("products/{productId:int}")]

上述Route的定義,即表明,既要符合products/{productId:int}的路由規(guī)則,又要是GET請(qǐng)求。

其實(shí)HTTPGET這一系列Attribute也可以在普通的MVC Controller上使用,因?yàn)樵贛VC6中,MVC Controller和Web API Controller本身就是同一個(gè)東西,只不過(guò)MVC的返回類(lèi)型都是IActionResult而已。

Route定義,不僅僅支持GET請(qǐng)求,還支持POST等其它類(lèi)型的請(qǐng)求,即不限制請(qǐng)求方式。

在HttpXXX系列特性中,也是支持內(nèi)聯(lián)參數(shù)和[controller]、[action]標(biāo)記位的,大可放心使用。

目前可用的特性類(lèi)有:HttpGet、HttpPost、HttpPut、HttpDelete、HttpPatch。

非要重要Route定義規(guī)則

基于Attribute的Route定義很方便,但也很危險(xiǎn),具體規(guī)則和危險(xiǎn)性如下。

規(guī)則1:Controller上定義了Route特性很危險(xiǎn)

一旦在Controller上定義了Route特性,該Controller下的所有路由規(guī)則都不受其它規(guī)則控制了,比如,如果你定義了類(lèi)似這樣的

  1. [Route("book")] 
  2. public class HomeController : Controller 
  3.     public IActionResult Index() 
  4.     { 
  5.         return View(); 
  6.     } 
  7.  
  8.     public IActionResult About() 
  9.     { 
  10.         ViewBag.Message = "Your application description page."
  11.         return View(); 
  12.     } 
  13. }

那么,上述2個(gè)Action你都再也沒(méi)辦法訪問(wèn)了,因?yàn)槟J(rèn)的action的名稱根本就不會(huì)起作用,即/book/index和/book/about這兩個(gè)路徑無(wú)法路由到對(duì)應(yīng)的Action方法上。而且/book也訪問(wèn)不了,因?yàn)橛袃蓚€(gè)以上的Action,系統(tǒng)無(wú)法定位到其中一個(gè)Action上。

所以要讓上述Action能訪問(wèn),必須要在其中一個(gè)Action上定義再Route,例如:

  1. [Route("book")] 
  2. public class HomeController : Controller 
  3.     public IActionResult Index() 
  4.     { 
  5.         return View(); 
  6.     } 
  7.  
  8.     [Route("about")] 
  9.     public IActionResult About() 
  10.     { 
  11.         ViewBag.Message = "Your application description page."
  12.         return View(); 
  13.     } 
  14. }

這樣,就可以通過(guò)/book/about來(lái)訪問(wèn)About方法了,而訪問(wèn)/book則可以訪問(wèn)默認(rèn)的index方法了,因?yàn)樵搃ndex方法是默認(rèn)唯一一個(gè)沒(méi)有定義路由的方法,所以他就是/book路由規(guī)則的默認(rèn)Action。如果,有3個(gè)Action的話,則必須要至少給兩個(gè)Action定義Route,示例如下:

  1. [Route("book")] 
  2. public class HomeController : Controller 
  3.     [Route("index")] 
  4.     public IActionResult Index() 
  5.     { 
  6.         return View(); 
  7.     } 
  8.  
  9.     [Route("about")] 
  10.     public IActionResult About() 
  11.     { 
  12.         ViewBag.Message = "Your application description page."
  13.         return View(); 
  14.     } 
  15.     public IActionResult Contact() 
  16.     { 
  17.         ViewBag.Message = "Your contact page."
  18.         return View(); 
  19.     } 
  20. }

此時(shí),Contact方法就是默認(rèn)/book路由的Action了,訪問(wèn)/book路徑的話,就會(huì)顯示Contact對(duì)應(yīng)的頁(yè)面。

規(guī)則2:Route和HttpGet可以一起使用,但也很危險(xiǎn)

我們前面提到,在Action上即可以使用Route特性,也可以使用HttpGet特性,兩者之間的不同,就是多了一個(gè)Http Method。很多同學(xué)可以要問(wèn)兩個(gè)特性在一起使用的時(shí)候會(huì)有問(wèn)題么?

其實(shí),這兩個(gè)特性是可以在一起使用的,示例如下:

  1. [Route("book")] 
  2. public class HomeController : Controller 
  3.     [Route("Contact")] 
  4.     [HttpGet("home/Contact2")] 
  5.     public IActionResult Contact() 
  6.     { 
  7.         ViewBag.Message = "Your contact page."
  8.  
  9.         return View(); 
  10.     } 
  11. }

這樣/book/contact和/book/home/contact2這兩個(gè)網(wǎng)址,都可以訪問(wèn)了。但如果這里定義HttpGet,情況就不一樣了,示例如下:

  1. [Route("Contact")] 
  2. [HttpPost("home/Contact2")]

此時(shí),訪問(wèn)該Action的方式,要么是以GET的方式訪問(wèn)/book/contact地址,要么是以POST的方式訪問(wèn)/book/home/contact2。所以為了避免出錯(cuò),建議使用的時(shí)候不要講兩者混用,即便是要同時(shí)支持GET和POST,那也是建議用同類(lèi)型的HttpXXX來(lái)定義這些路由,例如:

  1. [HttpGet("Contact")] 
  2. [HttpPost("home/Contact2")] 

這樣,看起來(lái)就清晰多了。

規(guī)則3:多個(gè)Route和多個(gè)HttpXXX也可以一起使用,但也很危險(xiǎn)

在如下示例中,我們?yōu)镠omeController定義了2個(gè)Route特性,而Contact定義了2個(gè)Route特性和1個(gè)HttpPost特性。


  1. [Route("book")] 
  2. [Route("tom")] 
  3. public class HomeController : Controller 
  4.     [Route("Contact")] 
  5.     [Route("ContactUS")] 
  6.     [HttpPost("home/Contact2")] 
  7.     public IActionResult Contact() 
  8.     { 
  9.         ViewBag.Message = "Your contact page."
  10.         return View(); 
  11.     } 
  12. }

那么,在上述代碼生效后,我們將有六種訪問(wèn)來(lái)訪問(wèn)該Action,這六種方式分布如下:

GET:/book/contact
GET:/book/contactus
GET:/tom/contact
GET:/tom/contactus
POST:/book/home/contact2
POST:/tom/home/contact2

但是,在視圖文件中,通過(guò)@Html.ActionLink("Contact", "Contact", "Home")生成鏈接地址的話,則默認(rèn)會(huì)使用***個(gè)定義的Route,如果要強(qiáng)制指定順序,則可以使用Order屬性來(lái)定義排序值,默認(rèn)會(huì)優(yōu)先使用最小的值。示例如下:

  1. [Route("book", Order = 1)] 
  2. [Route("tom", Order = 0)] 
  3. public class HomeController : Controller 
  4.     [Route("Contact", Order = 1)] 
  5.     [Route("ContactUS", Order = 0)] 
  6.     [HttpPost("home/Contact2", Order = 2)] 
  7.     public IActionResult Contact() 
  8.     { 
  9.         ViewBag.Message = "Your contact page."
  10.         return View(); 
  11.     } 

自定義內(nèi)聯(lián)參數(shù)約束

在前面的介紹中,我們知道任意類(lèi)型的路由在定義的時(shí)候都支持不同的內(nèi)聯(lián)參數(shù)約束,因?yàn)檫@些約束是基于ASP.NET 5的,而不是基于MVC6的,并且這些約束還是可以擴(kuò)展的,本節(jié)我們就來(lái)看看如何自定義一些擴(kuò)展。

無(wú)參數(shù)約束

首先,我們來(lái)看一個(gè)比較簡(jiǎn)單的約束,即無(wú)參數(shù)約束,類(lèi)似于{productId:int}這樣的類(lèi)型約束,假設(shè)我們要實(shí)現(xiàn)一個(gè)AABBCC字符串限定的約束,示例如下:

  1. [Route("index/{productId:aabbcc}")] 

為了確保/index/112233和/index/aabbcc是符合約束的,而/index/aabbccdd是不符合約束的,我們首先要自定義一個(gè)約束類(lèi)AABBCCRouteConstraint,并實(shí)現(xiàn)IRouteConstraint接口,示例如下:

  1. public class AABBCCRouteConstraint : IRouteConstraint 
  2.     public bool Match(HttpContext httpContext, IRouter route, string routeKey, IDictionary 

在該實(shí)現(xiàn)類(lèi)中,要實(shí)現(xiàn)Match方法,根據(jù)傳入的各種參數(shù),判斷是否符合定義的約束,并返回true或false,Match方法的參數(shù)中,其中routeKey是約束{productId:aabbcc}對(duì)應(yīng)的參數(shù)名稱(本例中是productId),values集合中會(huì)有該productId所對(duì)應(yīng)的數(shù)字(如112233),在該方法通過(guò)響應(yīng)的判斷返回true和false。

下一步,就是要將該約束類(lèi)注冊(cè)到Routing系統(tǒng)的約束集合中,在Startup.cs的ConfigureServices方法中,執(zhí)行如下語(yǔ)句:

  1. services.Configure(opt => {     opt.ConstraintMap.Add("aabbcc", typeof(AABBCCRouteConstraint)); });

注意,這里注冊(cè)的aabbcc就是前面我們所指定約束名稱,完成上述步驟以后,即可實(shí)現(xiàn)類(lèi)似{productId:int}的功能了。

有參數(shù)約束

一般情況下,有些時(shí)候可能需要定義一些約束的值,比如Length(1,10)來(lái)表示1-10之間的字符串長(zhǎng)度,舉例來(lái)說(shuō),加入我們要定義一個(gè)4個(gè)參數(shù)的約束規(guī)則,如abcd(1,10,20,30)來(lái)表示一個(gè)特殊的驗(yàn)證項(xiàng),則需要聲明有4個(gè)參數(shù)的構(gòu)造函數(shù),示例如下:

  1. public class ABCDRouteConstraint : IRouteConstraint 
  2.     public int A { get; private set; } 
  3.     public int B { get; private set; } 
  4.     public int C { get; private set; } 
  5.     public int D { get; private set; } 
  6.     public ABCDRouteConstraint(int a, int b, int c, int d) 
  7.     { 
  8.         A = a;B = b;C = c;D = d; 
  9.     } 
  10.  
  11.     public bool Match(HttpContext httpContext, IRouter route, string routeKey, IDictionary

假如你在Action上了定義了如下約束:

  1. [Route("index/{productId:abcd(1,20,30,40)}")]

那么,在注冊(cè)該約束類(lèi)型以后,系統(tǒng)啟動(dòng)厚掃描所有的Route進(jìn)行注冊(cè)的時(shí)候,會(huì)分析你定義的這4個(gè)值,然后會(huì)將這4個(gè)值賦值給該路由對(duì)應(yīng)的約束實(shí)例上的A、B、C、D四個(gè)屬性上,以便在HTTP請(qǐng)求過(guò)來(lái)的時(shí)候,分析URL上的值,看是否符合Match里定義的規(guī)則(在驗(yàn)證的時(shí)候就可以使用這4個(gè)屬性值)。

默認(rèn)約束的所有代碼可以參考:https://github.com/aspnet/Routing/tree/dev/src/Microsoft.AspNet.Routing/Constraints另外,如果定義了4個(gè)參數(shù)的約束,那么在action上定義路由的時(shí)候則必須符合參數(shù)的數(shù)據(jù)類(lèi)型,如果不符合,系統(tǒng)啟動(dòng)的時(shí)候就會(huì)出錯(cuò),示例錯(cuò)誤如下:

  1. [Route("index/{productId:abcd}")] //沒(méi)有為該對(duì)象定義無(wú)參數(shù)的構(gòu)造函數(shù) 
  2.  
  3. [Route("index/{productId:abcd(a)}")] 
  4. [Route("index/{productId:abcd('a')}")] //輸入字符串的格式不正確 
  5.  
  6. [Route("index/{productId:abcd(1,2,3)}")] //構(gòu)造函數(shù)的參數(shù)個(gè)數(shù)和定義的參數(shù)個(gè)數(shù)不一致。

如果你定義的參數(shù)類(lèi)型是字符串類(lèi)型,則下面2種形式的定義都是合法的:

  1. [Route("index/{productId:abcd(a,b,c,d)}")] 
  2. [Route("index/{productId:abcd('a','b','c','d')}")]

雖然ASP.NET 5 和MVC6的路由使用方式很簡(jiǎn)單,但是相關(guān)的使用規(guī)則卻很復(fù)雜,大家使用的時(shí)候需要多加注意。

責(zé)任編輯:chenqingxiang 來(lái)源: 湯姆大叔的博客
相關(guān)推薦

2015-06-18 16:29:14

ASP.NET

2015-06-17 14:42:04

ASP.NET

2015-06-29 10:00:02

ASP.NETMVC6

2015-06-18 17:04:22

ASP.NET

2015-06-18 16:39:17

ASP.NET

2015-06-16 15:01:59

ASP.NET 5

2015-06-17 16:45:28

ASP.NET

2015-06-17 16:01:30

ASP.NET

2015-06-17 17:01:48

ASP.NET

2015-06-17 16:04:36

ASP.NET

2015-06-18 17:37:19

ASP.NET

2015-06-17 10:16:30

ASP.NET

2015-06-18 14:25:56

ASP.NET

2015-06-17 14:09:36

ASP.NET

2014-08-26 09:22:40

ASP.NET MVCRouting

2015-06-17 14:16:50

ASP.NET

2015-06-17 14:18:50

ASP.NET

2015-06-18 17:34:25

ASP.NET

2009-03-12 10:42:38

RoutingIgnoreRouteASP.NET

2009-08-19 09:23:40

ASP.NET Rou
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)