ASP.NET MVC4在错误的区域中搜索控制器

Adm*_*vić 13 asp.net-mvc asp.net-mvc-3 asp.net-mvc-4

我正在使用默认的MVC路由设置:

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

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

我将区域定义为:

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 }
            );
        }
    }
Run Code Online (Sandbox Code Playgroud)

我在那个区域有一个控制器:

namespace XXX.Areas.Administration.Controllers
{
    public class CountryController : Controller
    {
        public ActionResult Index()
        {
///
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当我输入

/行政/国家

它按照需要工作得很好.

当我输入

/国家

动作仍然被调用,虽然找不到视图所以我收到错误.

为什么MVC接受

/国家

作为有效路线?我在非区域区域没有另一个CountryController.

Ima*_*ani 9

在Global.asax文件中添加NameSpace作为默认路由.

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

AreaRegistration在您的课程中添加NameSpaceArea

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" }
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

说明

我的申请表中有以下区域.所以下面突出显示的部分与控制器有关.好.

图1

在此输入图像描述

我输入了网址: http://localhost:2474/ActionFilterAttribute/index

在前往目的地之前.我将向您展示我如何初始化我的测试.我添加了RoureDebugger的参考.你可以从这个位置获得Dll.然后我在Application_StartHandler 下的Global.asax文件中添加了一行代码.

RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);
Run Code Online (Sandbox Code Playgroud)

所以,最后使用上面提到的Url,我开始调试应用程序.最后我看到了下图.



图-2

在此输入图像描述

动作仍然被调用,虽然找不到视图所以我收到错误.

回答

所以如果你注意上面突出显示的那么Route,这就是了Default Route.如上所述,该模式与Url匹配.但是在这种情况下将找不到View,这就是你Controller Action Method被调用的原因.


在转到下一部分之前,为什么我会得到404.我将向您展示我在示例应用程序中所做的一些测试.

我创建了一个派生自ActionFilterAttribute下面的类.这只包含一个Override被调用的OnResultExecuting.该Handler在执行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);
    }
}
Run Code Online (Sandbox Code Playgroud)

好.让我们回到最初的问题.为什么我会得到404?

在检查之前,您Controller将被默认的基本路由选中,因此将在而不是在中找到.{controller}/{action}Area RouteViewRoot/ViewsArea/views

为了检查这一点,我在区域内的Controller的Action方法中设置了调试器,发现DataToken当Requested url 没有时没有信息Area Name.让我们来看看更多细节DataTokenDebug模式


图-3

在此输入图像描述

如果你注意了ControllerContext,我列举了DataTokens,这显示没有键/值.这是因为没有找到与该控制器相关的视图Root Directory

怎么说现在的目录是根目录?证明如下




图-4

在此输入图像描述

值中没有提到名称空间或任何区域RouteData.对?

现在让我们转移到RouteData匹配包含的模式Area Name.所以,这次我的Url是:http://localhost:2474/mypractise/ActionFilterAttribute/index以下是RouteDataURLRoutingModule匹配的




图-5

在此输入图像描述

请注意突出显示的部分,这次Route匹配属于AreaName模式,匹配值为false,默认路由属于RouteDataRoot Directory中的某些路由.对?

关于DataTokens上述请求的Url,我的最终细节.您可以在此次查看命名空间详细信息和区域详细信息.


图-6

在此输入图像描述



结论:

Controller是区域内和你DataTokens没有显示的信息Area,NameSpace以及UseNameSpaceFallback信息.这意味着你将获得404.如图4所示,你所请求的Url是正确的,所以你得到了DataTokens和如图3所示,DataTokens没有显示,因为请求的Url不包含Area Name,尽管你事实上得到了RouteData图2中提到的,因为它是默认的Url模式.最后尝试执行第三行代码OnResultExecuting.它将显示null,因为找不到View.

希望这个解释能帮到你.


tec*_*osh 7

核实.修改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;
Run Code Online (Sandbox Code Playgroud)

编辑:

我很抱歉.这似乎是你想要它做的这个问题,以及知道为什么.

您遇到的问题是默认路由将查找任何控制器.即使它在一个区域.您可以通过简单地将namespaces参数添加到路由并指定默认路由应该使用控制器查找的内容来克服此默认行为.

如果您不想提供区域外部区域的视图,我上面提供的解决方案仅仅是一个修复.

还有为什么这是发生一个伟大的文章在这里.