2015-06-20 3 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>() }); 
} 

One для выбора всех пользователей, а другой для возврата всех пользователей. В веб-апи 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, который не учитывает параметры в действии, например, у вас была бы такая же проблема в MVC 5, если вы использовали Routes.MapRoute.

То же самое происходит в коде MVC 6, поскольку вы добавляете стандартный маршрут MVC с использованием routes.MapRoute. В обоих случаях структура обнаруживает 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 (предупреждение, непроверенный код):

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 мертвы –

Смежные вопросы