2015-06-20 126 views
4

我有2種方法超簡單的控制器:路由在MVC 6

public IActionResult Users(long id) 
{ 
    return Json(new { name = "Example User" }); 
} 

public IActionResult Users() 
{ 
    return Json(new { list = new List<User>() }); 
} 

之一,選擇所有用戶和其他返回的所有用戶。在網頁API 2我可以用戶以下的路徑,和一切工作得很好:

config.Routes.MapHttpRoute(
       name: "Users", 
       routeTemplate: "v1/Users", 
       defaults: new { action = "Users", controller = "Users" }, 
       constraints: null, 
       handler: new TokenValidationHandler() { InnerHandler = new HttpControllerDispatcher(config) } 
      ); 

我有以下的路線設置在startup.cs:

app.UseMvc(routes => 
      { 
       routes.MapRoute(name: "User_Default", template: "v1/{controller=Users}/{action=Users}/{id?}"); 
      }); 

但是這給了我一個AmbiguousActionException: Multiple actions matched. The following actions matched route data and had all constraints satisfied

我究竟做錯了什麼?

+0

我會猜測你的控制器上有一個屬性'Route',這在許多模板中都有。你能提供你的整個控制器嗎? –

+0

@MattDeKrey我不這樣認爲,如果我簡單地設置我的路線像webapi 2路線 – Gazeth

回答

6

在您原來的webapi代碼中,您使用的是Routes.MapHttpRoute,它添加了webapi特定路線。這與不考慮動作參數的MVC路線不同,例如,如果您使用的是Routes.MapRoute,則在MVC 5中會出現同樣的問題。

由於您使用routes.MapRoute添加了標準MVC路由,因此您的MVC 6代碼中發生了同樣的情況。在這兩種情況下,框架都會找到2個匹配相同路由的控制器操作,而沒有附加限制。它需要一些幫助才能選擇其中的一個。

來澄清對API操作最簡單的方法將使用屬性的路由,而不是確定的路線,如this example

[Route("v1/[controller]")] 
public class UsersController : Controller 
{ 
    [HttpGet("{id:int}")] 
    public IActionResult Users(long id) 
    { 
     return Json(new { name = "Example User" }); 
    } 

    public IActionResult Users() 
    { 
     return Json(new { list = new[] { "a", "b" } }); 
    } 
} 

有,將讓你改變了MVC路由的行爲的其他選項MVC 6.您可以創建自己的IActionConstraint屬性來強制執行有或沒有給定參數。這樣,這些行動之一,需要在路由id參數,而其他要求不能有一個ID參數(警告,未經測試的代碼):

public class UsersController : Controller 
{ 
    [RouteParameterConstraint("id", ShouldAppear=true)] 
    public IActionResult Users(long id) 
    { 
     return Json(new { name = "Example User" }); 
    } 

    [RouteParameterConstraint("id", ShouldNotAppear=true)] 
    public IActionResult Users() 
    { 
     return Json(new { list = new[] { "a", "b" } }); 
    } 
} 

public class RouteParameterConstraintAttribute : Attribute, IActionConstraint 
{ 
    private routeParameterName; 

    public RouteParameterConstraintAttribute(string routeParameterName) 
    { 
     this.routerParamterName = routerParameterName; 
    } 

    public int Order => 0; 
    public bool ShouldAppear {get; set;} 
    public bool ShouldNotAppear {get; set;} 

    public bool Accept(ActionConstraintContext context) 
    { 
     if(ShouldAppear) return context.RouteContext.RouteData.Values["country"] != null; 
     if(ShouldNotAppear) return context.RouteContext.RouteData.Values["country"] == null; 

     return true; 
    } 
} 

一個更好的選擇處理的WebAPI 2風格的控制器將增加約定到MVC管道中。這正是Microsoft.AspNet.Mvc.WebApiCompatShim正在幫助遷移webapi 2控制器。您可以看到添加的約定here。請查看this guide以便快速瀏覽此軟件包。

+0

我不認爲他們會需要我已經標記這是正確的答案,但我也想知道爲什麼指定在startup.cs文件路由不起作用 – Gazeth

+0

@Gazeth,我已添加更多詳細信息到我的答案 –

+0

鏈接https://github.com/aspnet/Mvc/blob/dev/src/Microsoft.AspNet.Mvc.WebApiCompatShim /WebApiCompatShimOptionsSetup.cs和https://www.asp.net/vnext/overview/aspnet-vnext/create-a-web-api-with-mvc-6已死亡 –