ASP.NET Web API路由是整個API的入口。咱們訪問某個資源就是經過路由映射找到對應資源的URL。經過URL來獲取資源的。html
對於ASP.NET Web API內部實現來說,咱們的請求最終將定位到一個具體的Action上。因此說,ASP.NET Web API路由就是把客戶端請求映射到對應的Action上的過程。web
模板路由是ASP.NET Web API默認提供的路由。下面咱們就簡單講解此中路由的用法。 正則表達式
默認模板路由 api
模板路由使用前須要定義路由模板。以下面默認的路由模板: post
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http; namespace Supernova.Webapi { public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 配置和服務 // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } } }
此模板路由是新建項目默認生成的,在App_Start文件夾下。測試
咱們能夠看到此模板的URL格式是api/{controller}/{id}。api表明在資源前面要帶上api目錄,controller表明請求資源的控制器名稱。id表明一條資源的id,id 是可選的。這種默認的模板是不帶action的,因此它是以請求方式來區分資源的,咱們必須在action上添加請求方式特性加以區分。 ui
1.咱們添加一個測試控制器api。 spa
public class TestController : ApiController { public object Get1() { return "d1"; } }
用fiddldr調試以下:設計
2.咱們添加兩個方法以下: 調試
public class TestController : ApiController { public object Get1() { return "d1"; } public object Get2() { return "d2"; } }
咱們再用fiddler調試以下:
錯誤信息是:
{"Message":"出現錯誤。","ExceptionMessage":"找到了與該請求匹配的多個操做: \r\n類型 Supernova.Webapi.Controllers.TestController 的 Get1\r\n類型 Supernova.Webapi.Controllers.TestController 的 Get2","ExceptionType":"System.InvalidOperationException","StackTrace":" 在 System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)\r\n 在 System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)\r\n 在 System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"}
咱們將代碼改成以下:
public class TestController : ApiController { public object Get1() { return "d1"; } [HttpPost] public object Get2() { return "d2"; } }
調試返回Get1的信息。
從上面兩個測試咱們能夠得出以下結論:
定製模板路由
咱們從新定製模板路由,以下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http; namespace Supernova.Webapi { public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 配置和服務 // Web API 路由 config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); } } }
從上面咱們能夠看出,在默認路由的基礎上,咱們隊路由模板增長了一級action。
測試api以下:
public class TestController : ApiController { public object Get1() { return "d1"; } public object Get2() { return "d2"; } }
咱們再經過http://192.168.0.230/api/test訪問,返回404,如圖:
咱們經過http://192.168.0.230/api/test/Get1訪問,結果正確,如圖:
咱們經過http://192.168.0.230/api/test/Get2訪問,結果正確,如圖:
經過定製路由模板咱們能夠得出以下結論:
特性路由是經過給action打attribute的方式定義路由規則。
有時候咱們會有這樣的需求,咱們請求的一個資源帶有子資源。好比文章評論這樣有關聯關係的資源。咱們但願經過以下URL得到某篇文章下的全部評論:api/book/id/comments。而僅僅憑藉模板路由很難實現這種路由模式。這時候咱們就須要特性路由來解決這個問題了。ASP.NET Web API爲咱們準備了Route特性,該特性能夠直接打到Action上,使用很是靈活、直觀。
下面我將先簡單的介紹特性路由的使用方法。
咱們從新定義api以下:
public class TestController : ApiController { [Route("demo")] [HttpGet] public object Get1() { return "d1"; } [Route("demo/get")] [HttpGet] public object Get2() { return "d2"; } }
咱們能夠看出,在action打上了標籤。
使用fiddler調試以下:
請求Get1的URL是http://192.168.0.230/demo
請求Get2的URL是http://192.168.0.230/demo/get
使用特性路由很簡單,不須要作額外的配置,只須要在action上打上Route標籤就能夠了。這樣模板路由就自動失效了。
以下:
public class TestController : ApiController { [Route("demo")] [HttpGet] public object Get1() { return "d1"; } [Route("demo/get")] [HttpGet] public object Get2() { return "d2"; } }
有時候咱們想對某個資源的全部操做都加上一個統一的前綴。
第一種方式:
public class TestController : ApiController { [Route("api/demo")] [HttpGet] public object Get1() { return "d1"; } [Route("api/demo/get")] [HttpGet] public object Get2() { return "d2"; } }
這種方式看起來還能夠哈,就是有點弱智。那麼咱們就可使用RoutePrefix將特性加在controller上面,那麼對資源的請求就要加上api目錄了。
第二種方法:
[RoutePrefix("api")] public class TestController : ApiController { [Route("demo")] [HttpGet] public object Get1() { return "d1"; } [Route("demo/get")] [HttpGet] public object Get2() { return "d2"; } }
3.2中的方法能夠對某個資源的前面統一加上 前綴。那麼問題來了,若是咱們還會有這樣的需求,個人某個資源中的大部分請求都須要前綴,可是就是有那麼一兩個資源不須要加前綴,腫麼辦?其實微軟早就給咱們想到了,人家說了,固然容許你重寫action前綴啊。
以下代碼,咱們從新了Get1:
[RoutePrefix("api")] public class TestController : ApiController { [Route("~/demo")] [HttpGet] public object Get1() { return "d1"; } [Route("demo/get")] [HttpGet] public object Get2() { return "d2"; } }
用fiddler調試以下:
報錯了吧,正確的URL實際上是:http://192.168.0.230/demo
如今問題又來了,那麼多的請求,特別是Get請求方式,都須要帶參數啊,怎麼定義參數的類型,長度範圍等約束條件呢?
答案是能夠經過"{參數變量名稱:約束}"來約束路由中的參數變量。
ASP.NET Web API內置約束包括:
{x:alpha} 約束大小寫英文字母
{x:bool}
{x:datetime}
{x:decimal}
{x:double}
{x:float}
{x:guid}
{x:int}
{x:length(6)}
{x:length(1,20)} 約束長度範圍
{x:long}
{x:maxlength(10)}
{x:min(10)}
{x:range(10,50)}
{x:regex(正則表達式)}
以下代碼:
[RoutePrefix("api")] public class TestController : ApiController { [Route("demo/{id:int}")] [HttpGet] public object Get1() { return "d1"; } [Route("demo/{name}")] [HttpGet] public object Get2() { return "d2"; } }
以上,若是片斷變量id爲int類型,就路由到第一個Action Get1,若是不是,路由到第二個Action Get2。
使用fiddler調試以下:
請求是Get1.
請求的是Get2
能夠爲一個參數變量同時設置多個約束:
以下代碼:
[RoutePrefix("api")] public class TestController : ApiController { [Route("demo/{id:int:min(5)}")] [HttpGet] public object Get1() { return "d1"; } [Route("demo/{name}")] [HttpGet] public object Get2() { return "d2"; } }
請求URL:http://192.168.0.230/api/demo/1 定位到Get2
實現IHttpRouteConstraint接口,可自定義約束規則。實現一個不能爲0的約束。
代碼以下:
public class NonZeroConstraint : IHttpRouteConstraint { public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary<string, object> values, HttpRouteDirection routeDirection) { object value; if (values.TryGetValue(parameterName, out value) && value != null) { long longValue; if (value is long) { longValue = (long)value; return longValue != 0; } string valueString = Convert.ToString(value, CultureInfo.InvariantCulture); if (Int64.TryParse(valueString, NumberStyles.Integer, CultureInfo.InvariantCulture, out longValue)) { return longValue != 0; } } return false; } }
在App_Start文件夾中的WebApiConfig中註冊自定義約束。必需要註釋原先的模板路由
public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API 配置和服務 // Web API 路由 //config.MapHttpAttributeRoutes(); //config.Routes.MapHttpRoute( // name: "DefaultApi", // routeTemplate: "api/{controller}/{action}/{id}", // defaults: new { id = RouteParameter.Optional } //); var constraintResolver = new DefaultInlineConstraintResolver(); constraintResolver.ConstraintMap.Add("nonzero", typeof(NonZeroConstraint)); config.MapHttpAttributeRoutes(constraintResolver); } }
測試代碼以下:
[RoutePrefix("api")] public class TestController : ApiController { [Route("demo/{id:nonzero}")] [HttpGet] public object Get1() { return "d1"; } [Route("demo/{name}")] [HttpGet] public object Get2() { return "d2"; } }
使用URL:http://192.168.0.230/api/demo/0 定位到Get2
有時候,咱們請求的參數是可選的,怎麼辦呢,咱們就須要給參數設置默認值來處理了。
代碼以下:
[RoutePrefix("api")] public class TestController : ApiController { [Route("demo/{id:int?}")] [HttpGet] public object Get1(int id=1) { return "d1"+id; } [Route("demo/{name}")] [HttpGet] public object Get2() { return "d2"; } }
當參數不存在或者爲int類型時定位的是Get1,當參數存在不爲int時定位的是Get2.
URL:http://192.168.0.230/api/demo 定位 Get1
URL:http://192.168.0.230/api/demo/2 定位 Get1
URL:http://192.168.0.230/api/demo/abc 定位 Get2
[RoutePrefix("api")] public class TestController : ApiController { [Route("demo/{id:int?}",Name="經過ID獲取內容")] [HttpGet] public object Get1(int id = 1) { return "d1" + id; } [Route("demo/{name}")] [HttpGet] public object Get2() { return "d2"; } }
Route特性設置的路由優先順序是根據慣例和RouteOrder屬性來肯定的。
慣例是:
一、靜態片斷變量
二、帶約束的片斷變量
三、不帶約束的片斷變量
四、帶約束的通配符片斷變量
五、不帶約束的通配符片斷變量
RouteOrder屬性的默認值是0,屬性值越小,排在越前面。
測試代碼以下,按照優先級來的:
[RoutePrefix("api")] public class TestController : ApiController { [Route("orders/detail", Name = "靜態片斷變量")] [HttpGet] public object Get1() { return "orders/detail"; } [Route("orders/{id:int}", Name = "帶約束的片斷變量")] [HttpGet] public object Get2(int id) { return "orders/{id:int}"; } [Route("orders/{name}", Name = "不帶約束的片斷變量")] [HttpGet] public object Get3(string name) { return "orders/{name}"; } [Route("orders/lily", Order = 1)] [HttpGet] public object Get4() { return "orders/lily"; } }
URL:http://192.168.0.230/api/orders/detail 定位 Get1 靜態片斷變量 Order=0
URL:http://192.168.0.230/api/orders/lily定位 Get3 帶約束的片斷變量 Order=0
URL:http://192.168.0.230/api/orders/1定位 Get2 不約束的片斷變量 Order=0
Get3包含了Get4的定義,因此說永遠也沒法定義到Get4。這也是在特性路由中須要特別注意的地方。
1.URL中不能出現動詞。
參考:
http://www.eggtwo.com/news/detail/155
https://docs.microsoft.com/en-us/aspnet/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api
http://www.cnblogs.com/n-pei/archive/2012/07/17/2595352.html