ASP.NET WebApi 路由配置

ASP.NET Web API路由是整個API的入口。我們訪問某個資源就是通過路由映射找到對應資源的URL。通過URL來獲取資源的。

對於ASP.NET Web API內部實現來講,我們的請求最終將定位到一個具體的Action上。所以說,ASP.NET Web API路由就是把客戶端請求映射到對應的Action上的過程。

 路由分爲兩種模式:模板路由和特性路由。

1.模板路由

模板路由是ASP.NET Web API默認提供的路由。模板路由使用前需要定義路由模板。如下面默認的路由模板:

複製代碼
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 }
            );
        }
    }
}
複製代碼

我們可以看到此模板的URL格式是api/{controller}/{id}。api代表在資源前面要帶上api目錄,controller代表請求資源的控制器名稱。id代表一條資源的id,id 是可選的。這種默認的模板是不帶action的,所以它是以請求方式來區分資源的,我們必須在action上添加請求方式特性加以區分。

我們添加一個測試控制器api:

複製代碼
public class TestController : ApiController
    {
        public object Get1()
        {
            return "d1";
        }       
    }
複製代碼

我們添加兩個方法如下:

複製代碼
public class TestController : ApiController
    {
        public object Get1()
        {
            return "d1";
        }
        public object Get2()
        {
            return "d2";
        }
    }
複製代碼

錯誤信息:

{"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的信息。

 

從上面兩個測試我們可以得出如下結論:

action的默認請求方式是HttpGet。
當多個action的 請求方式一樣的話,在默認路由模板下(沒有action),將會匹配多個操作。
基於上面兩點結論,默認路由模板無法滿足針對一種資源一種請求方式的多種操作(比如修改操作,可能針對不同的字段進行修改)。

我們重新定製模板路由,如下:

複製代碼
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目錄,對資源的定位直接作用到action上。
多個HttpGet方法可以共存於一個controller中。
基於上面兩點結論,通過修改路由模板可以滿足針對一種資源一種請求方式的多種操作。

 

2.特性路由

特性路由是通過給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";
        }
    }
複製代碼

請求Get1的URL是http://192.168.0.230/demo

請求Get2的URL是http://192.168.0.230/demo/get

有時候我們想對某個資源的所有操作都加上一個統一的前綴:

複製代碼
[RoutePrefix("api")]
    public class TestController : ApiController
    {
        [Route("demo")]  
        [HttpGet]
        public object Get1()
        {
            return "d1";
        }
       [Route("demo/get")]
       [HttpGet]
        public object Get2()
        {
            return "d2";
        }
    }
複製代碼

如果我們還會有這樣的需求,我的某個資源中的大部分請求都需要前綴,但是就是有那麼一兩個資源不需要加前綴:

複製代碼
 [RoutePrefix("api")]
    public class TestController : ApiController
    {
        [Route("~/demo")]  
        [HttpGet]
        public object Get1()
        {
            return "d1";
        }
       [Route("demo/get")]
       [HttpGet]
        public object Get2()
        {
            return "d2";
        }
    }
複製代碼

現在問題又來了,那麼多的請求,特別是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。

可以爲一個參數變量同時設置多個約束:

複製代碼
[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

 

參考資料:http://www.eggtwo.com/news/detail/155

 

發佈了29 篇原創文章 · 獲贊 43 · 訪問量 30萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章