Asp.net mvc 2 ASP.NET MVC 2 RC 2在未指定区域时返回特定于区域的控制器

Asp.net mvc 2 ASP.NET MVC 2 RC 2在未指定区域时返回特定于区域的控制器,asp.net-mvc-2,routes,areas,Asp.net Mvc 2,Routes,Areas,我有一个基本的MVC2(RC2)站点,有一个基本层控制器(“主页”),一个区域(“管理员”)有一个控制器(“摘要”)。当我调用-管理员区域中的抽象控制器被调用,即使我没有在URL中指定该区域。更糟糕的是,它似乎不知道它在Admin下,因为它找不到关联的视图,只返回: The view 'Index' or its master was not found. The following locations were searched: ~/Views/Abstract/Index.aspx ~/V

我有一个基本的MVC2(RC2)站点,有一个基本层控制器(“主页”),一个区域(“管理员”)有一个控制器(“摘要”)。当我调用-管理员区域中的抽象控制器被调用,即使我没有在URL中指定该区域。更糟糕的是,它似乎不知道它在Admin下,因为它找不到关联的视图,只返回:

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

我做错什么了吗?这是虫子吗?功能?

您的路由设置正确吗?当您使用区域时,您必须手动更改路由代码,以便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
}

我和我的朋友在ASP.NET MVC 2中遇到了同样的问题。我们发现了一个“黑客”,到目前为止,似乎正在发挥作用。对于tl;dr version,请参见此答案的底部

在“Admin”区域的“AdminAreaRegistration.cs”类中,您可能有类似于以下内容的内容:

因此,当您请求“”时,“Admin_default”路由与请求不匹配应该是合理的。因此,根据设计,MVC框架尝试将请求与任何其他定义的路由相匹配。如果您在VisualStudio中使用MVC工具创建web项目,您将在“Global.asax”文件(在web项目的根目录下)中定义一个“默认”路由。它应该类似于这样:

// 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}
    );
}
“Default”路由成功地将“”的请求与“controller”=“Abstract”、“action”=“Index”(默认值)和“id”=“urlparmeter.Optional”(默认值)匹配。这是正确的、有意的行为。。。到目前为止

现在,MVC框架将尝试加载“抽象”控制器。根据设计,MVC将搜索一个名为“AbstractController”的类,该类将“Controller”扩展到web项目的文件/命名空间层次结构中的任何位置。需要注意的是,控制器的文件位置和名称空间不会影响MVC查找它的能力;换句话说,仅仅因为您将“AbstractController”放在名为“Areas\Admin\Controllers”的文件夹中,并将名称空间更改为“Web.Areas.Admin.Controllers”,而不是说“Web.Controllers”,并不意味着MVC不会使用它

当MVC在“AbstractController”中执行“Index”操作时,它很可能只返回“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
我们和您一样,不希望“”请求解析为“Admin”区域的“AbstractController”;只有“”应该起作用。我想不出为什么会有人想要这种行为

一个简单的解决方案是删除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
    );
}
没有。对“”的请求仍将在“Admin”区域中使用“AbstractController”,即使“AbstractController”的命名空间是“Web.Areas.Admin.Controllers”,并且(显然)不是“Web.Controllers”。这完全令人困惑;看起来这个白名单对MVC的控制器分辨率没有不可预测的影响

-tl;dr answer从这里开始-

经过一些黑客攻击,我们发现了如何强制MVC只使用白名单名称空间中的控制器

将“默认”路由上DataTokens字典的“UseNamespaceFallback”键设置为false。现在,当我们请求“”时,“默认”路由仍将匹配(这是有效的行为!),但MVC不会使用任何不在定义的命名空间内的控制器;在这种情况下,只有“Web.Controllers”命名空间中的控制器有效。最后,这是我们一直在寻找的功能!我们无法理解为什么这不是默认行为。奇怪吧


希望这能有所帮助。

Haack的文章主要是关于清除围绕重复控制器名称的问题。我已尝试将默认控制器名称空间添加到默认路由,但没有帮助。对于它的真正作用,似乎存在一些困惑:有些人认为它只是优先考虑某个名称空间,但所有其他名称空间仍然会被搜索。你们对此有何看法:haack基本上是说我的问题是设计问题,唯一的解决方法是硬编码路由到默认名称空间中的每个控制器?如上所述哈克评论的链接是错误的。正确的一点:如果没有看到你在你的区域和主要站点中定义的路线,就不可能知道。谢谢你的详细回复。我见过最好的答案。我已经求助于硬编码路由到我所有的根控制器。这是一个很好的答案。。事实上,我只是遇到了同样的行为,并对此感到非常惊讶。
// 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
}