2010-02-27 1 views
1

Я определил следующий маршрут для простого блога.Проблема с использованием Url.Action() при попытке создать дружественные и «взломанные» URL-адреса

routes.MapRoute(
    "Blog", 
    "blog/{year}/{month}/{day}", 
    new { controller = "Blog", action = "Index" }, 
    new { year = @"\d{4}", month = @"\d{2}", day = @"\d{2}" } 
); 

URL-адрес должен быть в состоянии "взломать", чтобы выполнить следующие действия:

Я создал контроллер, который прекрасно справляется с этим действием. Однако мне не удается создать ссылки в моих представлениях, используя Url.Action().

К примеру этого ...

var d = new DateTime(2010, 1, 25); 
Url.Action("Index", "Blog", new { year=d.Year, month=d.Month, day=d.Day}); 

... генерирует URL, как это выглядит следующим образом:

http://abc.com/blog?year=2010&month=2&day=21

Я предпочел бы, как это генерировать url, который похож на URL-адреса в списке выше.

http://abc.com/blog/2010/02/21

Есть ли способ, что я могу использовать Url.Action() или Html.ActionLink() для создания URL-адресов в формате я хочу?

ответ

3

Проблема в том, что месяц, в течение которого вы проходите до Url.Action, является одноразрядным месяцем и, следовательно, не соответствует ограничениям месяца в определении маршрута. Ограничения обычно выполняются не только по входящим URL-адресам, но также при создании URL-адресов.

Исправление будет связано с ручным вызовом .ToString() в месяце и отформатировать его как двузначное число. Вам нужно будет сделать то же самое и в течение дня. В течение года это не проблема, поскольку все годы нашей жизни будут четырехзначными числами.

Вот пример кода для форматирования чисел:

int month = 2; 
string formattedMonth = month.ToString("00", CultureInfo.InvariantCulture); 
// formattedMonth == "02" 

Пожалуйста, обратите внимание, что при ручном форматировании число, которое вы должны использовать Инвариантные культуру так, что различные культуры и языки не будут влиять, как он получает отформатирован.

Вам также необходимо установить значения по умолчанию для месяца и дня, чтобы они не требуются в URL:

routes.MapRoute( 
    "Blog", 
    "blog/{year}/{month}/{day}", 
    new { controller = "Blog", action = "Index", month = "00", day = "00" }, 
    new { year = @"\d{4}", month = @"\d{2}", day = @"\d{2}" } 
); 

И в чеке действия контроллера, если месяц или день являются 0, в котором случае вы должны показать целый месяц или целый год.

+0

Вы пригвоздили его. Спасибо за Ваш ответ. Отлично работает. – jessegavin

0

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

«http://abc.com/2010« не соответствует »блогу/{году}/{месяцу}/{день}". Это очень специфический маршрут, который требует трех параметров (с ограничениями) для соответствия. Для того чтобы принять те другие маршруты, которые вы должны создать другие записи маршрута вдоль линий:

routes.MapRoute(
    null, 
    "blog", 
    new { controller = "Blog", action = "Index", year = 0000, month = 00, day = 00 }, 
    new { year = @"\d{4}", month = @"\d{2}", day = @"\d{2}" } 
); 

routes.MapRoute(
    null, 
    "blog/{year}", 
    new { controller = "Blog", action = "Index", month = 00, day = 00 }, 
    new { year = @"\d{4}" } 
); 

routes.MapRoute(
    null, 
    "blog/{year}/{month}", 
    new { controller = "Blog", action = "Index", day = 00 }, 
    new { year = @"\d{4}", month = @"\d{2}"} 
); 

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

Быстрый пример:

if(year == 0000 && month == 00 && day == 00) 
    var posts = postsRepository.GetAllPost(); 
else if(year != 0000 && month == 00 && day == 00) 
    var posts = postsRepository.GetPostsByYear(year); 

...

+1

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

+0

+1 для краткости и общей удивительности. Если я буду честен после довольно тяжелого использования MVC, я не знал, что это возможно. Я думал, что если маршрут был принят, он отправил значения по умолчанию независимо от того, что, но после быстрого теста ваше сокращенное решение отлично работает. –

+0

Для этого вам не нужно несколько маршрутов. Маршрут, который я показываю в своем описании вопроса, работает чудесно. (Мой вопрос был больше связан с тем, как Url.Action() создает URL-адрес для соответствия этому маршруту.) – jessegavin

0

Вы не должны писать новый метод для всех условия. Я имею в виду, что вы можете сделать это с этим;

например. для NHibernate.

public IList<Blog> GetBlogs(int? day, int? month, int? year) { 
    IQueryable<Blog> iQBlog = Session.Linq<Blog>(); 

    if (year.HasValue) { 
     iQBlog = iQBlog.Where(b => b.Year == year); 

     if (month.HasValue) { 
      iQBlog = iQBlog.Where(b => b.Month == month); 

      if (day.HasValue) { 
       iQBlog = iQBlog.Where(b => b.Day == day); 
      } 
     } 
    } 

    return iQBlog.ToList(); 
} 

пс. Он проверяет параметры шаг за шагом, год -> месяц -> день. Если пользователь не задает никаких параметров в querystring, он вернет все блоги.

+0

Это то, что я уже делаю. Мой вопрос был больше связан с маршрутизацией Url. – jessegavin

+0

Yup я понял ваш вопрос, но уже ответил, и он/она делает это с новыми методами. Я сказал это, потому что, возможно, это поможет вам – cem

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

  • Нет связанных вопросов^_^