2016-09-20 54 views
2

我有兩個控制器如下:異常[RoutePrefix]行爲的WebAPI

[RoutePrefix("v1/user/something")] 
public class SomethingsController : ApiController 
{ 
    [Route("{id}")] 
    [HttpGet] 
    [ResponseType(typeof(SomethingsViewModel))] 
    public async Task<IHttpActionResult> GetAsync([FromUri]int id) 
    { 
    } 
} 

[RoutePrefix("v1/user")] 
public class UserController : ApiController 
{ 
    [Route("{id}")] 
    [HttpGet] 
    [Authorize(Roles = "Super Admin")] 
    public async Task<IHttpActionResult> GetByIdAsync([FromUri]int id) 
    { 
    } 
} 

現在通過看上面的代碼,我會認爲正在創建以下兩個途徑:

  • V1 /用戶/事/(編號)
  • V1 /用戶/(編號)

但不幸的是,由於某些原因,就是沒有案件。嘗試訪問以上某個路由時,我總是收到以下異常消息:

找到了與URL匹配的多種控制器類型。如果多個控制器上的屬性路由匹配請求的URL,就會發生這種情況 請求發現下列匹配的控制器類型:MyProject.Api.Controllers.UserController,MyProject.Api.Controllers.SomethingsController

請幫我在盤算什麼,我可能是做錯了或小的細節是我錯過了這裏。

+0

在屬性路由的情況下,Web API會嘗試查找與請求匹配的所有控制器。如果它看到多個控制器能夠處理這個問題,那麼它會拋出一個異常 –

+0

@Div我知道,但問題是,如果你看看上面的代碼,多個控制器不應該能夠處理它,因爲有RoutePrefix是不同的。 – haseebahmed7

+0

@ haseebahmed7儘管他們的路線前綴是不同的他們解決路線匹配。例如'v1/user/{id}',匹配'v1/user/something/{id}',其中第一個路由中的id參數arg將採用'something/{id}'。路由前綴和路由屬性組合起來創建一個添加到路由表的完整路由。 – Nkosi

回答

3

雖然他們的路由前綴是不同的,他們解決路線匹配。例如v1/user/{id}將與v1/user/something/{id}匹配,其中id參數arg在第一路由中將取something/{id}

路由前綴和路由屬性合併在一起,以創建一個添加到路由表的完整路由。

在這種情況下,您需要使用約束條件才能更好地區分路線。

[RoutePrefix("v1/user/something")] 
public class SomethingsController : ApiController { 
    [Route("{id:int}")] 
    [HttpGet] 
    [ResponseType(typeof(SomethingsViewModel))] 
    public async Task<IHttpActionResult> GetAsync([FromUri]int id) { ... } 
} 

[RoutePrefix("v1/user")] 
public class UserController : ApiController { 
    [Route("{id:int}")] 
    [HttpGet] 
    [Authorize(Roles = "Super Admin")] 
    public async Task<IHttpActionResult> GetByIdAsync([FromUri]int id) { ... } 
} 

所以現在與int約束something不會被誤認爲是有效的參數爲UserController.GetByIdAsync行動

參考Attribute Routing in ASP.NET Web API 2: Route Constraints

路由約束

路由約束讓你限制如何路線中的參數模板匹配。一般語法是「{參數:約束}」。 例如:

[Route("users/{id:int}"] 
public User GetUserById(int id) { ... } 

[Route("users/{name}"] 
public User GetUserByName(string name) { ... } 

這裏,第一路徑將只選擇如果 URI的「ID」段是一個整數。否則,將選擇第二條路線。