【问题标题】:ASP.NET MVC 2 RC 2 returns Area-specific controller when no area specifiedASP.NET MVC 2 RC 2 在未指定区域时返回特定于区域的控制器
【发布时间】:2011-01-19 20:21:20
【问题描述】:

我有一个基本的 MVC 2 (RC2) 站点,其中包含一个基本控制器(“Home”)和一个区域(“Admin”)和一个控制器(“Abstract”)。当我调用http://website/Abstract 时,即使我没有在 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

我做错了吗?这是一个错误吗?一个功能?

【问题讨论】:

  • 你们对此有何看法:stackoverflow.com/questions/2314524/… 基本上是在说我的问题是设计使然,解决它的唯一方法是将路由硬编码到默认命名空间中的每个控制器?
  • 以上链接到 haack 的评论是错误的。正确的一个:stackoverflow.com/questions/1639971/…
  • 如果看不到您在您所在区域和主站点中定义的路线,就无法判断。

标签: asp.net-mvc-2 routes areas


【解决方案1】:

我和我的朋友在使用 ASP.NET MVC 2 中的区域时遇到了同样的问题。我们发现了一个“hack”,到目前为止,它似乎正在运行。对于 tl;dr 版本,请参阅此答案的底部。

您的“Admin”区域的“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 框架会尝试将请求与任何其他已定义的路由进行匹配。如果您使用 Visual Studio 中的 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”路由成功匹配“http://website/Abstract”的请求,“controller”=“Abstract”,“action”=“Index”(默认值),“id”=UrlParameter.Optional(默认值)。这是正确的、预期的行为......到目前为止。

现在,MVC 框架将尝试加载“抽象”控制器。按照设计,MVC 将搜索名为“AbstractController”的类,该类在 Web 项目的文件/命名空间层次结构中的任何位置扩展“Controller”。需要注意的是,Controller 的文件位置和命名空间不会影响 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

我们和您一样,不希望对“http://website/Abstract”的请求解析为“Admin”区域的“AbstractController”;只有“http://website/Admin/Abstract”才能工作。我想不出为什么有人会想要这种行为。

一个简单的解决方案是删除 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
    );
}

不。即使“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
}

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

希望这会有所帮助。

【讨论】:

  • 感谢您的详细回复。我见过的最佳答案。我只使用硬编码路由到我所有的根控制器。
  • 这是一个很好的答案。我刚刚遇到了同样的行为,真的很惊讶,实际上。
【解决方案2】:

您是否正确设置了路由?当您使用区域时,您必须手动更改路由代码,以便 MVC 查找正确的命名空间。

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

【讨论】:

  • Haack 的文章主要是关于清除重复控制器名称的问题。我已经尝试将默认控制器命名空间添加到我的默认路由,但它没有帮助。似乎对于它的真正作用有些困惑:stackoverflow.com/questions/721700/… 有些人认为它只是优先考虑某个命名空间 - 但所有其他命名空间仍然会被搜索。
猜你喜欢
  • 2010-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-17
  • 2011-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多