2010-01-16 5 views
1

У меня есть контроллер с именем Movie, с действием имени ByYear, которая занимает год в качестве параметра:Как определить этот маршрут в ASP.NET MVC?

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: /Кино/ByYear/{ год}, но единственным действительным маршрутом для этого действия является следующее: /Movie/ByYear? year = {year}.

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

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

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

ответ

9

Изменить имя от вашего параметра 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 для этого конкретного действия. Поэтому, чтобы исправить это, у вас есть два варианта:

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

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

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

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

EDIT 2: Еще одна вещь, которую следует отметить, заключается в том, что механизм маршрутизации остановится на первом найденном маршруте, который соответствует вашему запросу, поэтому любые настраиваемые маршруты, подобные этому, должны быть добавлены до по умолчанию, поэтому вы уверены, что они будут быть найденным.

+1

Но я не * хочу * назвать это id ... это не идентификатор, это год. Я не хочу разрушать ясность моего кода, чтобы сделать систему маршрутизации MVC счастливой;). Во всяком случае, я нашел ответ через несколько минут после отправки моего вопроса ... –

+1

@Thomas. Действие называется ByYear. Я не думаю, что ясность будет разрушена путем изменения параметра переменной. С другой стороны, переход от маршрутов по умолчанию не помогает ремонтопригодности. –

+0

Да, решение с новым маршрутом - это то, что я в итоге придумал ... Но значит ли это, что мне придется создавать новые маршруты каждый раз, когда я создаю действие с новыми именами параметров?! Спасибо за объяснение в любом случае –

4

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

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

EDIT: Не существует более простой способ? (не связано с переименованием параметров). Я хотел бы быть в состоянии сделать что-то подобное:

[Route("/Movie/ByYear/{year}")] 
public ActionResult ByYear(int year) 
{ 
    ... 
+2

Хотя это правильно, я был бы склонен идти с ответом Скотта, чтобы поддерживать минимальное количество маршрутов, насколько это возможно. И изменение, необходимое для этого, было бы довольно простым. –

+0

Да, я вижу вашу точку зрения ... но называть параметр «id», когда это на самом деле год, может быть действительно запутанным, и я определенно этого не хочу. –

+0

Существует не более простой способ, поскольку он должен знать контроллер и, к сожалению, не знает, как получить это из URL. У меня тоже была эта проблема, и мне не нравилось вызывать все параметры моего контроллера «id» только для соответствия таблице маршрутизации, поэтому я сделал то, что вы сделали –

2

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

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

Этот маршрут будет соответствовать гораздо большему, чем контроллер Movie и ByYear. Я нахожу, что маршруты должны быть как можно более конкретными, когда вы добавляете новые, просто потому, что есть много побочных эффектов. –

+0

+1 для ограничения регулярных выражений ... У меня действительно есть чему узнать о MVC;) –

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