路由在MVC 6

问题描述:

我有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

在您原来的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已死亡 –