ASP.NET MVC 2 RC 2 возвращает специфичный для области контроллер, если область не указана - PullRequest
5 голосов
/ 23 февраля 2010

У меня есть базовый сайт MVC 2 (RC2) с одним контроллером базового уровня («Домашний») и одной областью («Администратор») с одним контроллером («Абстрактный»). Когда я звоню http://website/Abstract - вызывается абстрактный контроллер в области администратора, хотя я не указал область в URL. Что еще хуже - он, кажется, не знает, что находится под Администратором, потому что не может найти связанный вид и просто возвращает:

The view 'Index' or its master was not found. The following locations were searched:
~/Views/Abstract/Index.aspx
~/Views/Abstract/Index.ascx
~/Views/Shared/Index.aspx
~/Views/Shared/Index.ascx

Я что-то не так делаю? Это ошибка? Особенность?

Ответы [ 2 ]

11 голосов
/ 07 мая 2010

У меня и моего друга была такая же проблема с областями в ASP.NET MVC 2. Мы нашли «хак», который, похоже, работает. Версия tl; dr приведена в нижней части этого ответа.

Возможно, у вас есть что-то похожее на следующее в классе AdminAreaRegistration.cs вашей области:

// Web/Areas/Admin/AdminAreaRegistration.cs

public override void RegisterArea(AreaRegistrationContext context) {
    context.MapRoute(
        "Admin_default",
        "Admin/{controller}/{action}/{id}",
        new { action = "Index", id = UrlParameter.Optional }
    );
}

Таким образом, должно иметь смысл, что когда вы делаете запрос для "http://website/Abstract",", маршрут "Admin_default" не совпадает с запросом. Таким образом, структура MVC пытается сопоставить запрос с любым другим определенные маршруты. Если вы использовали инструмент MVC в Visual Studio для создания своего веб-проекта, у вас будет маршрут по умолчанию, определенный в файле «Global.asax» (в корне вашего веб-проекта). Он должен выглядеть аналогично на это:

// Web/Global.asax.cs

public static void RegisterRoutes(RouteCollection routes) {
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

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

Маршрут "По умолчанию" успешно сопоставляет запрос для "http://website/Abstract", с" controller "=" Abstract "," action "=" Index "(значение по умолчанию) и" id "= UrlParameter.Optional (значение по умолчанию). Это правильное и предполагаемое поведение ... пока.

Теперь инфраструктура MVC попытается загрузить «абстрактный» контроллер. По замыслу MVC будет искать класс с именем «AbstractController», который расширяет «Controller» в любом месте иерархии файлов / пространств имен веб-проекта. Важно отметить, что местоположение файла и пространство имен Контроллера не влияют на способность MVC найти его; другими словами, просто потому, что вы поместили «AbstractController» в папку «Areas \ Admin \ Controllers» и изменили пространство имен на «Web.Areas.Admin.Controllers» вместо, скажем, «Web.Controllers» , не означает, что MVC не будет его использовать.

Когда MVC выполняет действие «Index» в «AbstractController», которое, скорее всего, просто возвращает «View ()», тогда MVC сбивается с толку, поскольку не знает, где найти представление «Index». Поскольку MVC совпал с необластным маршрутом (маршрут «По умолчанию» в Global.asax), он считает, что соответствующий вид должен находиться в папках беззонального представления. Таким образом вы получите знакомое сообщение об ошибке:

The view 'Index' or its master was not found. The following locations were searched:
~/Views/Abstract/Index.aspx
~/Views/Abstract/Index.ascx
~/Views/Shared/Index.aspx
~/Views/Shared/Index.ascx

Мы, как и вы, не хотели, чтобы запросы для "http://website/Abstract" разрешались в" AbstractController "области администратора; должен работать только" http://website/Admin/Abstract". Я не могу понять, почему кто-то хотел бы такого поведения.

Простое решение состоит в том, чтобы удалить маршрут "Default" в Global.asax, , но , это нарушит все обычные не-зональные контроллеры / представления. Это, вероятно, не вариант для большинства людей ...

Итак, мы подумали, что можем ограничить набор контроллеров, которые MVC будет использовать для запросов, соответствующих маршруту «По умолчанию» в Global.asax:

// Web/Global.asax.cs

public static void RegisterRoutes(RouteCollection routes) {
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default",
        "{controller}/{action}/{id}",
        new {controller = "Home", action = "Index", id = UrlParameter.Optional},
        new[] {"Web.Controllers"} // Added this line
    );
}

Неа. Запрос "http://website/Abstract" будет все еще использовать" AbstractController "в области" Администратор ", даже если пространство имен" AbstractController "равно" Web.Areas.Admin.Controllers "и ( очевидно, не "Web.Controllers". Это полностью сбивает с толку, кажется, что этот белый список не оказывает существенного влияния на разрешение контроллера MVC.

- tl; д-р ответ начинается здесь -

После некоторого взлома мы выяснили, как заставить MVC использовать контроллеры только в пространствах имен, включенных в белый список.

// Web/Global.asax.cs

public static void RegisterRoutes(RouteCollection routes) {
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default",
        "{controller}/{action}/{id}",
        new {controller = "Home", action = "Index", id = UrlParameter.Optional},
        new[] {"Web.Controllers"}
    ).DataTokens["UseNamespaceFallback"] = false; // Added this line
}

Установите ключ «UseNamespaceFallback» словаря DataTokens на маршруте «По умолчанию» в значение false. Теперь, когда мы сделаем запрос на «http://website/Abstract",», маршрут «По умолчанию» будет по-прежнему соответствовать (это допустимое поведение!), Но MVC не будет использовать любой контроллер, который не находится в пределах определенного namespace (s), в этом случае допустимы только контроллеры в пространстве имен "Web.Controllers". Наконец, это та функция, которую мы искали! Мы не можем понять, почему это не поведение по умолчанию. да?

Надеюсь, это поможет.

1 голос
/ 23 февраля 2010

Правильно ли вы настроили свою маршрутизацию? Когда вы используете области, вы должны вручную изменить код маршрутизации, чтобы MVC просматривал правильные пространства имен.

http://haacked.com/archive/2010/01/12/ambiguous-controller-names.aspx

...