Подтвердить что ты не робот

ASP.NET MVC4 Поиск контроллера в неправильной области

Я использую настройку маршрутизации MVC по умолчанию:

        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

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

У меня есть область, определяемая как:

public class AdministrationAreaRegistration : AreaRegistration
    {
        public override string AreaName
        {
            get
            {
                return "Administration";
            }
        }

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

И у меня есть контроллер в этой области:

namespace XXX.Areas.Administration.Controllers
{
    public class CountryController : Controller
    {
        public ActionResult Index()
        {
///
        }
    }
}

Когда я печатаю

/Администрирование/Страна

он работает хорошо, как это желательно.

Когда я печатаю

/Страна

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

Почему MVC принимает

/Страна

как действительный маршрут? У меня нет другого CountryController в зоне без зоны.

4b9b3361

Ответ 1

Добавьте поле NameSpace в файл Global.asax для маршрута по умолчанию.

var route = routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}", // URL with parameters
    new { controller = "Home", action = "Index" }, // Parameter defaults,
    new[] { "YourNameSpace.Controllers" }
);

Добавить имя в пространстве AreaRegistration в Area

public class MyArea : AreaRegistration
{
    public override void RegisterArea(AreaRegistrationContext context)
    {
        context.MapRoute(
            "test",
            "Test/{controller}/{action}/{id}",
            new { action = "Index", id = UrlParameter.Optional },
            new[] { "MyProjectNameSpace.Controllers" }
        );
    }
}

Объяснение

У меня есть следующая область в моем приложении. Поэтому приведенный ниже выделенный раздел касается Controller. ок.

Рисунок -1

enter image description here

Я набрал Url: http://localhost:2474/ActionFilterAttribute/index

Перед тем, как перейти к пункту назначения. Я покажу вам, как я инициализировал свой тест. Я добавил ссылку RoureDebugger. Вы можете получить Dll из этого места. Затем я добавил строку кода в файл Global.asax в Application_Start Handler.

RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);

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

в Рисунок -2

enter image description here

Вопрос

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

Ответ

Итак, если вы обратите внимание на выделенное выше Route, ну, это Default Route. Этот шаблон сопоставляется с Url, как указано выше. Но View не будет найден в этом случае и что причина, по которой вызывается Controller Action Method.


Прежде чем перейти к следующей части, почему я получил 404. Я покажу вам несколько тестов, которые я сделал в своем примере приложения.

Я создал класс, который получается из ActionFilterAttribute, как показано ниже. Это содержит только один Override, который называется OnResultExecuting. Этот обработчик выполняет перед выполнением View, соответствующей конкретному Action

Цель создания этого класса - просто проверить, что происходит с RouteData и DataTokens.

public class MyActionFilter : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        var viewResult = filterContext.Result as ViewResult;

        if (viewResult != null)
        {
            var razorEngine = viewResult
                                        .ViewEngineCollection
                                        .OfType<RazorViewEngine>()
                                        .Single();

            var viewName = !String.IsNullOrEmpty(viewResult.ViewName) ? 
                                                  viewResult.ViewName :         
                  filterContext.RouteData.Values["action"].ToString();

           var razorview = razorengine
                           .FindView
                           (
                               filtercontext.Controller.ControllerContext, 
                               viewname, 
                               viewResult.MasterName, 
                               false
                           ).View as RazorView;
        }

        base.OnResultExecuting(filterContext);
    }
}

Ok. Вернемся к первоначальному вопросу. Почему я получил 404?

Ваш Controller будет выбран базовым маршрутом по умолчанию {controller}/{action}, прежде чем он проверит Area Route и поэтому будет искать View в Root/Views, а не в Area/views.

Чтобы проверить это, я установил отладчик в Action Method of Controller внутри Area и обнаружил, что нет DataToken Information, если запрошенный url не имеет Area Name. более подробно о DataToken в Debug режиме


Рисунок -3

enter image description here

Если вы обратите внимание на ControllerContext, я перечислил DataTokens, который не отображает ключ/значение. Это потому, что не обнаружено никакого представления относительно этого контроллера в Root Directory

Как вы можете сказать, что расположенный в данный момент каталог - это Root Directory? Доказательство ниже




Рисунок -4

enter image description here

Не существует ни пространства имен, ни какого-либо Района, указанного в значениях RouteData. не так ли?

Теперь перейдем к RouteData, который соответствует шаблону, содержащему Area Name. Итак, на этот раз мой Url: http://localhost:2474/mypractise/ActionFilterAttribute/index, а ниже RouteData соответствует URLRoutingModule




Рисунок -5

enter image description here

Обратите внимание на выделенный раздел, на этот раз сопоставленный маршрут принадлежит шаблону AreaName, а совпадающее значение false для маршрута по умолчанию, которое принадлежит некоторому RouteData в Root Directory. Правильно?

Мои последние данные для DataTokens в случае вышеупомянутого запрошенного Url. На этот раз вы можете увидеть детали пространства имен и информацию о регионе.


Рисунок -6

enter image description here

в Заключение:

Когда Controller находится внутри Района, а ваш DataTokens не отображает информацию для Area, NameSpace и UseNameSpaceFallback информации. Это означает, что вы получите 404. Как упоминалось на рисунке 4, ваш запрошенный URL был правильным, поэтому вы получили DataTokens и как указано на рисунке 3, DataTokens не были показаны, потому что запрошенный Url не содержит Area Name и несмотря на то, что вы получили RouteData, как указано на рисунке 2, потому что это шаблон Url по умолчанию. Наконец, попробуйте выполнить третью строку кода в OnResultExecuting. Он покажет null, потому что View не найден.

Надеюсь, что это объяснение поможет вам.

Ответ 2

Проверьте это. Измените маршрут по умолчанию в файле Global.ascx.cs таким образом.

var route = routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
    namespaces: new string[] { "APPLICATION_NAMESPACE.Controllers.*" }
);

route.DataTokens["UseNamespaceFallback"] = false;

EDIT:

Мои извинения. Казалось, вы не хотели, чтобы это делалось так же хорошо, как и почему.

Вы сталкиваетесь с тем, что маршрутизация по умолчанию будет искать все, что является контроллером. Даже если это в Районе. Вы можете преодолеть это поведение по умолчанию, просто добавив параметр namespaces к маршруту и ​​определите, какую маршрутизацию по умолчанию следует искать с контроллерами.

Решение, которое я изложил выше, является просто исправлением, если вы хотите не обслуживать представление области вне самой области.

Существует отличная статья о том, почему это происходит здесь.