Почему Asp.net MVC не может различать два действия, когда они имеют разные параметры?

Я пытаюсь иметь два разных метода для регистрации учетной записи в моем приложении MVC Asp.net, один для обычных пользователей для регистрации, а другой для пользователей, которые регистрируются с определенным регистрационным токеном. Таким образом, у меня есть следующие сигнатуры методов в моем AccountController:

public virtual ActionResult Register () {...}

public virtual ActionResult Register (Guid registrationToken) {...}

Однако, когда я перехожу к http://localhost/Account/Register, я получаю исключение, что текущий запрос неоднозначен между этими двумя действиями. У меня создалось впечатление, что он использовал бы безпараметрическое действие Register, если бы не был передан параметр registrationToken GET, иначе он будет использовать второй.

Требуется ли для этого специальная настройка маршрута?

Ответы

Ответ 1

Было бы проще иметь один метод с параметром nullable? Это также автоматически решит вашу проблему, поскольку она не будет неоднозначной:

public virtual ActionResult Register (Guid? registrationToken)
{
    if(registrationToken.HasValue)
    {
         // this is specific user
    }         
    else
    {
         // this is general user
    }
}

Ответ 2

Стандартный базовый класс для контроллеров mvc, Controller использует ActionInvoker, чтобы выбрать действие для вызова. Сначала действие выбрано, по умолчанию из значения RouteData [ "action" ], а затем все привязки и проверки модели для выбранных параметров действия происходят. Поэтому, когда invoker видит два действия с тем же именем и одинаковыми атрибутами для выбора, он запускает ошибку, так как не может различать два.

Но существует встроенный способ управления логикой выбора действий, то есть с использованием атрибутов, полученных из класса ActionMethodSelector. Сначала вы создаете из него класс, содержащий логику для вызова действия. В вашем случае

он будет использовать без параметров Зарегистрировать действие, если не было registrationToken GET параметр прошел в, иначе он будет использовать второй.

 public class RegistrationActionTokenAttribute : ActionMethodSelectorAttribute
    {
        public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
        {
            if (controllerContext.HttpContext.Request.QueryString.AllKeys.Contains("registrationToken"))
            {
                return true;
            }
            return false;
        }
    }

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

[RegistrationActionToken]    
public virtual ActionResult Register (Guid registrationToken) {...}

И ошибка исчезла. Кроме того, теперь контроллер выбирает правильное действие, в зависимости от параметра строки запроса

Ответ 3

Требуется ли второй метод Post? Обычно полезно добавить [HttpPost] выше любого метода, который будет использоваться для приема отправки формы.

И это также может решить вашу проблему.