Как определить этот маршрут в ASP.NET MVC?

У меня есть контроллер с именем Movie с действием ByYear, которое принимает год в качестве параметра:

    public ActionResult ByYear(int year)
    {
        ViewData["Title"] = string.Format("Movies released in {0}", year);
        var repository = MvcApplication.GetRepository();
        var movies = repository.Medias
                                .OfType<Movie>()
                                .Where(m => m.Year == year);
        return View("Index", movies);
    }

Я хочу получить доступ к этому действию по следующему URL-адресу: / Movie / ByYear / {year}, но единственный допустимый маршрут для этого действия: / Movie / ByYear? Year = {год}.

Я попытался добавить новые маршруты в метод RegisterRoutes своего приложения, но не могу найти способ получить желаемый результат ...

Может ли кто-нибудь сказать мне, как этого добиться?

Примечание: на самом деле это очень похоже на этот вопрос, но ответ не был принят, и ответ, получивший наибольшее количество голосов, не имеет для меня смысла, поскольку я совершенно новичок в MVC ...


person Thomas Levesque    schedule 16.01.2010    source источник


Ответы (3)


Измените имя вашего параметра year на id, и это будет соответствовать маршруту по умолчанию, который MVC добавляет в ваш проект.

Итак, для дальнейшего пояснения давайте взглянем на маршрут по умолчанию, добавленный ASP.NET MVC:

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

На этом маршруте вы можете увидеть три токена, которые названы специально для controller, action, а третий токен, который передается в действие, - id. Когда запрос поступает в ваше приложение, ASP.NET MVC анализирует маршруты, которые в настоящее время сопоставлены, и пытается найти сигнатуру метода, которая соответствует им, используя отражение для ваших контроллеров.

Когда он смотрит на ваш Movie контроллер, он видит действие с именем ByYear, однако этот метод принимает целое число с именем year, а не id. Вот почему вы получаете что-то вроде /Movie/ByYear?year={year}, когда вы создаете ActionLink для этого конкретного действия. Итак, чтобы исправить это, у вас есть два варианта:

Первый и самый простой способ исправить это - просто изменить сигнатуру метода для вашего действия, чтобы он принял параметр с именем id, что я рекомендовал выше. Это будет работать нормально, но я вижу, где это может вызвать небольшую путаницу, когда вы позже вернетесь к этому источнику и задаетесь вопросом, почему вы вызвали этот параметр id.

Второй метод - добавить еще один маршрут, соответствующий сигнатуре этого метода. Для этого вы должны открыть свой Global.asax и просто добавить следующее (не проверено, но должно работать):

routes.MapRoute(
    "MoviesByYear",
    "Movies/ByYear/{year}",
    new { controller = "Movie", action = "ByYear" }
);

Да, этот маршрут жестко запрограммирован, но он не нарушит другие маршруты в вашей системе и позволит вам вызвать параметр метода year.

РЕДАКТИРОВАТЬ 2: Следует также отметить, что механизм маршрутизации остановится на первом найденном маршруте, который соответствует вашему запросу, поэтому любые настраиваемые маршруты, подобные этому, должны быть добавлены перед маршрутом по умолчанию, чтобы вы были уверены, что они будет найден.

person Scott Anderson    schedule 16.01.2010
comment
Но я не хочу называть это id ... это не id, это год. Я не хочу портить ясность своего кода только для того, чтобы порадовать систему маршрутизации MVC;). Во всяком случае, я сам нашел ответ через несколько минут после публикации своего вопроса ... - person Thomas Levesque; 16.01.2010
comment
@Томас. Акция называется ByYear. Я не думаю, что изменение параметра переменной может испортить ясность. С другой стороны, уход от маршрутов по умолчанию не способствует ремонтопригодности. - person Dan Atkinson; 16.01.2010
comment
Да, решение с новым маршрутом - это то, что я в конце концов придумал ... Но означает ли это, что мне придется создавать новые маршруты каждый раз, когда я создаю действие с новыми именами параметров ?! В любом случае спасибо за объяснение - person Thomas Levesque; 16.01.2010
comment
Да, именно поэтому большинство людей решают пойти с id :) - Добавление дополнительных маршрутов не всегда лучшее решение, но не обязательно зло. Только будьте осторожны и обязательно тщательно их протестируйте. - person Scott Anderson; 16.01.2010
comment
Кроме того, если подумать, id означает идентификатор, верно? Что вы используете для определения фильмов в акции «По годам»? - person Scott Anderson; 16.01.2010
comment
Хорошо, вы правы ... Я, наверное, рассмотрю это решение;) - person Thomas Levesque; 16.01.2010
comment
Кроме того, ничто не мешает вам добавить комментарий поверх сигнатуры метода: P // used "id" here to match the default route - person Scott Anderson; 16.01.2010
comment
Кстати, насколько сильно влияет на производительность создание множества маршрутов? - person Thomas Levesque; 16.01.2010
comment
Эта статья дает хорошее представление о производительности ASP.NET MVC и, в частности, о маршрутизации: codeclimber.net.nz/archive/2009/04/17/ - person Scott Anderson; 16.01.2010

Хорошо, я только что узнал, как это сделать. Мне просто нужно было создать новый маршрут до маршрута по умолчанию ... Я не думал, что порядок имеет какое-то значение

        routes.MapRoute(
            "MovieByYear",                                          // Route name
            "Movie/ByYear/{year}",                                  // URL with parameters
            new { controller = "Movie", action = "ByYear" }         // Parameter defaults
        );

РЕДАКТИРОВАТЬ: Нет более простого способа? (без переименования параметров). Я бы хотел сделать что-то подобное:

[Route("/Movie/ByYear/{year}")]
public ActionResult ByYear(int year)
{
    ...
person Thomas Levesque    schedule 16.01.2010
comment
Хотя это правильно, я был бы склонен пойти с ответом Скотта, чтобы поддерживать минимальное количество маршрутов, насколько это возможно. И изменение, необходимое для этого, будет довольно простым. - person Dan Atkinson; 16.01.2010
comment
Да, я понимаю вашу точку зрения ... но наименование идентификатора параметра, когда на самом деле это год, может быть очень запутанным, и я определенно не хочу этого. - person Thomas Levesque; 16.01.2010
comment
Нет более простого способа, поскольку он должен знать контроллер и, к сожалению, не знает, как получить это из URL-адреса. У меня тоже была эта проблема, и мне не нравилось вызывать все идентификаторы параметров моего метода контроллера только для соответствия таблице маршрутизации, поэтому я сделал то, что вы сделали - person Chris S; 16.01.2010
comment
маршрутизация через атрибуты метода - определенно мой предпочтительный способ ... stackoverflow.com/questions/894779/ - person dotjoe; 15.07.2010

Помимо конструктивных соображений, если вы не хотите переименовывать параметр, вы можете добавить что-то вроде маршрута ниже, который требует наличия параметра года.

routes.MapRoute(
     "MovieByYear",                        // Route name
     "Movie/ByYear/{year}",       // URL with parameters
     new { controller = "Movie", action = "ByYear" },
     new { year = @"\d+" }                 // Parameter defaults
);
person Bob Palmer    schedule 16.01.2010
comment
Этот маршрут будет соответствовать гораздо большему, чем контроллер Movie и действие ByYear. Я считаю, что маршруты должны быть как можно более конкретными при добавлении новых просто потому, что есть много побочных эффектов. - person Scott Anderson; 16.01.2010
comment
+1 для ограничения регулярного выражения ... Мне действительно нужно многое узнать о MVC;) - person Thomas Levesque; 16.01.2010