Почему эти два Действия считаются двусмысленными, несмотря на то, что параметры различны?

Текущий запрос действия "Индекс" на тип контроллера "UsersController" неоднозначен между следующими методами действий: System.Web.Mvc.ActionResult PostUser (Models.SimpleUser) для типа Controllers.UsersController System.Web.Mvc.ActionResult PostUser (Int32, Models.SimpleUser) для типа Controllers.UsersController

Случается, когда я пытаюсь POST website.com/users/со значениями формы.

Когда нет NO ID (website.com/users/), я хочу, чтобы он создал нового пользователя, когда есть ID (/users/51, например), я хочу, чтобы он обновил этого пользователя, так как я могу заставьте разницу между этими двумя действиями?

Вот два действия:

    [HttpPost]
    [ActionName("Index")]
    public ActionResult PostUser(SimpleUser u)
    {

        return Content("User to be created...");
    }

    [HttpPost]
    [ActionName("Index")]
    public ActionResult PostUser(int id, SimpleUser u)
    {

        return Content("User to be updated...");
    }

Вот MapRoute:

    routes.MapRoute(
        "Users",
        "users/{id}",
        new { controller = "Users", action = "Index" }
    );

Ответ 1

Основная проблема заключается в некоторой двусмысленности между двумя вашими действительными методами, поскольку привязка к модели не помогает отменить конфигурацию маршрутизации. Ваша текущая маршрутизация просто указывает на метод индекса.

У вас все еще может быть один и тот же URL-адрес, но было бы полезно назвать ваши действия по-разному, а затем применить некоторые новые маршруты.

[HttpPost]
public ActionResult Create(SimpleUser u)
{
    return Content("User to be created...");
}

[HttpPost]
public ActionResult Edit(int id, SimpleUser u)
{
    return Content("User to be updated...");
}

И затем в вашей маршрутизации попробуйте

routes.MapRoute(
    "UserEdit",
    "users/{id}",
    new { controller = "Users", action = "Edit", 
        httpMethod = new HttpMethodConstraint("POST") });

routes.MapRoute(
    "UserCreate",
    "users",
    new { controller = "Users", action = "Create", 
        httpMethod = new HttpMethodConstraint("POST") });

Маршруты будут ограничены только событиями POST, что означает, что вы можете добавить некоторую маршрутизацию для своих методов GET на том же маршруте. Например, для списка или чего-то еще.

Ответ 2

Вы должны устранить неоднозначность своих методов, указав два разных имени действия.

Что вы можете сделать, чтобы иметь RESTful API, это создать свой собственный класс RouteHandler, который изменит маршрутизацию, в зависимости от того, присутствует ли значение {id}. Класс RouteHandler прост:

using System.Web.Mvc;
using System.Web.Routing;

  public class MyRouteHandler : IRouteHandler
  {
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
      var routeData = requestContext.RouteData;
      if (routeData.Values("id").ToString() == "0" /* our default invalid value */ )
      {
        var action = routeData.Values("action");
        routeData.Values("action") = action + "Add";
      }
      var handler = new MvcHandler(requestContext);
      return handler;
    }
  }

Затем измените RegisterRoutes() в Global.asax.cs следующим образом:

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        AreaRegistration.RegisterAllAreas();

        routes.Add("Default", new Route("{controller}/{action}/{id}",
            new RouteValueDictionary(
                new { controller = "Home", 
                      action = "Index", 
                      id = "0" /* our default invalid value */ }),
            new MyRouteHandler()));
    }

Наконец, измените атрибут ActionName для вашего метода "Добавить" на "IndexAdd". Когда запрос поступит без идентификатора, будет предоставлено недопустимое значение по умолчанию, которое предупредит ваш RouteHandler об изменении метода на ваш метод "Добавить".

counsellorben

Ответ 3

Было бы лучше, если вы захотите использовать действия Create и Edit для достижения желаемого. Как правило, индекс может использоваться для перечисления всех пользователей (в вашем случае). О проблеме, с которой вы сталкиваетесь, возникает потому, что нет маршрута, который не принимает никакого идентификатора в качестве параметра.