Баг с роутингом в ASP.NET MVC под 4-ый .NET Framework


Полгода назад я нашёл странный баг в ASP.NET MVC 2 под .NET Framework 4. Сегодня у меня наконец дошли руки разобраться в чём там дело и как это обойти.

Итак, мы имеем следующий Route:
routes.MapRoute(
                "Archive", // Route name
                "archive/{year}/{month}/{day}", // URL with parameters
                new { controller = "Archive", action = "Overview", year = UrlParameter.Optional, month = UrlParameter.Optional, day = UrlParameter.Optional }, // Parameter defaults
                new { year = @"(\d\d\d\d)?", month = @"\d?\d?", day = @"\d?\d?" }
            );
и хотим построить Url одним из следующих способов:
Url.RouteUrl("Archive");
Url.RouteUrl("Archive", new {year = "2011"});
Url.RouteUrl("Archive", new {year = "2011", month = "10"});
Url.RouteUrl("Archive", new {year = "2011", month = "10", day = "5"});
Под .NET Framework 3.5 всё работает отлично, RouteUrl возвращает правильные значения. Но стоит только сменить версию .NET Framework-а на 4-ую, как обнаруживается, что первые два RouteUrl-а возвращают null. После ряда экспериментов, я пришёл к выводу, что под 4-ым .NET Framework-ом опциональным может быть только один параметр, причём последний. Поскольку такое положение вещей меня не устраивало, то я обошёл данной ограничение "в лоб", создав несколько роутов для разного количества параметров:
routes.MapRoute(
                "Archive", // Route name
                "archive", // URL with parameters
                new { controller = "Archive", action = "Overview");
routes.MapRoute(
                "ArchiveYear", // Route name
                "archive/{year}", // URL with parameters
                new { controller = "Archive", action = "Overview", year = UrlParameter.Optional}, // Parameter defaults
                new { year = @"(\d\d\d\d)?"}
            );
routes.MapRoute(
                "ArchiveMonth", // Route name
                "archive/{year}/{month}", // URL with parameters
                new { controller = "Archive", action = "Overview", year = UrlParameter.Optional, month = UrlParameter.Optional}, // Parameter defaults
                new { year = @"(\d\d\d\d)?", month = @"\d?\d?"}
            );
routes.MapRoute(
                "ArchiveDay", // Route name
                "archive/{year}/{month}/{day}", // URL with parameters
                new { controller = "Archive", action = "Overview", year = UrlParameter.Optional, month = UrlParameter.Optional, day = UrlParameter.Optional }, // Parameter defaults
                new { year = @"(\d\d\d\d)?", month = @"\d?\d?", day = @"\d?\d?" }
            );
И соответственно Url-ы следует получать таким образом:
Url.RouteUrl("Archive");
Url.RouteUrl("ArchiveYear", new {year = "2011"});
Url.RouteUrl("ArchiveMonth", new {year = "2011", month = "10"});
Url.RouteUrl("ArchiveDay", new {year = "2011", month = "10", day = "5"});
Решение не самое красивое, но других вариантов обойти этот странный баг я на данный момент не нашёл. На Microsoft Connect есть данный баг для ASP.NET MVC3 RC2, но никакого решения не приведено.

КОММЕНТАРИИ


Карпович СВ
Карпович СВ 20.06.2011 14:33:09 #1
похожая беда, похоже беда в классе RouteValuesHelpers в методе MergeRouteValues,
if (routeValues != null) {
foreach (KeyValuePair<string, object> routeElement in GetRouteValues(routeValues)) {
mergedRouteValues[routeElement.Key] = routeElement.Value;
}
}
Похоже параметры мержатся с параметрами текущего контекста

НОВЫЙ КОММЕНТАРИЙ


*жирный*
_курсив_
+подчеркнутый+
! заголовок 1
!! заголовок 2
* список
** список 2
# нумерованый список
## нумерованый список 2
[url:http://www.example.com]
{"без форматирования"}
Полное описание синтаксиса