Проблема с использованием Url.Action () при попытке создать дружественные и «взломанные» URL - PullRequest
1 голос
/ 27 февраля 2010

Я определил следующий маршрут для простого блога.

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 ]

3 голосов
/ 27 февраля 2010

Проблема в том, что месяц, в который вы передаете 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 голосов
/ 28 февраля 2010

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

например. для 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();
}

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

0 голосов
/ 28 февраля 2010

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

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

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);

...

...