Конфликт маршрутизации ASP.NET MVC - нулевое значение для входной переменной - PullRequest
6 голосов
/ 09 февраля 2010

Я в недоумении, почему мои маршруты конфликтуют. У меня есть это в моем файле Global.asax:

        routes.MapRoute(
        "CustomerView", "{controller}/{action}/{username}",
        new { controller = "Home", action = "Index", username = "" }
        );

        routes.MapRoute(
        "Default", "{controller}/{action}/{id}",
        new { controller = "Home", action = "Index", id = "0" }
        );

Пока что все работало нормально, кроме случаев, когда я создал действие контроллера следующим образом:

    public ActionResult MyAction(int id)
    {
        //Do stuff here
        return View();
    }

Когда я пытаюсь просмотреть его через http://mydomain/MyController/MyAction/5, я получаю:

Ошибка сервера в приложении '/'.

Словарь параметров содержит пустая запись для параметра 'id' из необнуляемый тип 'System.Int32' для метод 'System.Web.Mvc.ActionResult Track (Int32) 'в 'InTouch.Controllers.OrderController. Чтобы сделать параметр необязательным, его тип должен быть либо ссылочным типом, либо Обнуляемый тип. Имя параметра: Параметры

предполагает, что значение id не читается должным образом. Конечно, когда я поменяюсь местами, порядок маршрутов вокруг него работает нормально. До сих пор мое (по общему признанию ограниченное) понимание состояло в том, что, если имя переменной, указанное в маршруте, совпадает с тем, которое указано в определении действия контроллера, оно будет предполагать его независимо от порядка. Видимо я был не прав. Обмен заказа приводит к сбою других действий контроллера. Как правильно обрабатывать мои маршруты в этом случае?

Ответы [ 2 ]

13 голосов
/ 09 февраля 2010

Проблема с вашим примером заключается в том, что совпадение происходит на первом маршруте, и он видит «5» в качестве параметра имени пользователя. Вы можете использовать ограничения, чтобы ограничить значения, принимаемые для каждого параметра, для достижения желаемого. Поскольку маршрут «Default», который принимает Id, является более ограничительным, чем маршрут «CustomerView», я бы сначала перечислил маршрут «Default» с ограничением на параметр Id:

routes.MapRoute(
    "Default", "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = "0" },
    new { id = @"\d+" } 
    );

Это приведет к тому, что первый маршрут будет совпадать, только если Id является целочисленным значением. Все остальные запросы затем будут перенаправлены на маршрут CustomerView, который будет принимать любые другие запросы, у которых нет целых чисел в качестве этого третьего параметра.

Извлечение Создание ограничения маршрута для объяснения ограничений.

2 голосов
/ 09 февраля 2010

Мое (по общему признанию, ограниченное) понимание до сих пор это было, если имя переменной указанный в маршруте соответствует тому, что указано в действии контроллера определение, это будет предполагать, что один независимо от порядка.

Привязка значений маршрута к аргументам действия происходит ПОСЛЕ того, как среда определяет, какой маршрут использовать. Выбор маршрута выполняется с использованием эвристики «первое совпадение выигрывает»: используется первый маршрут, который может успешно соответствовать входящему запросу, даже если позже был определен «лучший» маршрут.

Решение Майкла верное. Сначала необходимо указать маршрут по умолчанию, используя ограничения маршрута, чтобы сопоставлять только те URL-адреса, где идентификатор является числовым. Ваш второй, менее ограничительный маршрут должен последовать.

ПРИМЕЧАНИЕ : если вы следуете решению Михаэля, у вас возникнут проблемы, если у вас есть пользователи с именем пользователя, состоящим только из цифр. Вы могли бы подумать о добавлении к маршрутам какого-либо другого различающего фактора, например, добавив ключевое слово «пользователь» во 2-й:

routes.MapRoute(
    "Default", "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = "0" },
    new { id = @"\d+" } 
 );

routes.MapRoute(
    "CustomerView", "{controller}/{action}/user/{username}",
    new { controller = "Home", action = "Index", username = "" }
);
...