当未指定区域时,ASP.NET MVC 2 RC 2 返回特定于区域的控制器
我有一个基本的 MVC 2 (RC2) 站点,其中包含一个基础级控制器(“Home”),以及一个区域(“Admin”)和一个控制器(“Abstract”)。当我调用 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
我做错了什么吗?这是一个错误吗?一个特点?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我和我的朋友在 ASP.NET MVC 2 中的区域中遇到了同样的问题。我们发现了一个“hack”,到目前为止,它似乎有效。对于 tl;dr 版本,请参阅此答案的底部。
您的“Admin”区域的“AdminAreaRegistration.cs”类中可能有类似于以下内容的内容:
因此,当您请求“http://website/Abstract",“Admin_default”路由与请求不匹配。因此,根据设计,MVC 框架会尝试将请求与任何其他定义的路由进行匹配。如果您使用 Visual Studio 中的 MVC 工具创建 Web 项目,则您将在“Global.asax”文件(位于 Web 项目的根目录)中定义“默认”路由。它看起来应该与此类似:
“默认”路由成功匹配“http://website/Abstract”的请求,其中“controller”=“Abstract”、“action”=“Index”(默认值)和“id”= UrlParameter.Optional(默认值)。到目前为止,这是正确的、预期的行为。
现在,MVC 框架将尝试加载“抽象”控制器。根据设计,MVC 将搜索名为“AbstractController”的类,该类将“Controller”扩展至 Web 项目的文件/命名空间层次结构中的任何位置。需要注意的是,Controller 的文件位置和命名空间不会影响 MVC 找到它的能力;换句话说,只是因为您将“AbstractController”放置在名为“Areas\Admin\Controllers”的文件夹中,并将命名空间更改为“Web.Areas.Admin.Controllers”,而不是“Web.Controllers” ,并不意味着MVC不会使用它。
当 MVC 在“AbstractController”中执行“Index”操作(很可能只返回“View()”)时,MVC 会感到困惑,因为它不知道在哪里可以找到“Index”视图。因为 MVC 匹配了非区域路由(Global.asax 中的“默认”路由),所以它认为匹配的视图应该位于非区域视图文件夹中。因此,您会收到熟悉的错误消息:
我们和您一样,不希望请求“http://website/Abstract”解析为“Admin”区域的“AbstractController”;只有“http://website/Admin/Abstract”应该有效。我无法想象为什么有人会想要这种行为。
一个简单的解决方案是删除 Global.asax 中的“默认”路由,但是这会破坏任何常规的非区域控制器/视图。对于大多数人来说,这可能不是一个选择...
因此,我们认为我们可以限制 MVC 用于与 Global.asax 中的“默认”路由匹配的请求的控制器集:
不。对“http://website/Abstract”的请求将仍然在“Admin”区域,即使“AbstractController”的命名空间是“Web.Areas.Admin.Controllers”并且(显然)不是“Web.Controllers”。这实在令人困惑;看起来这个白名单对 MVC 的控制器分辨率没有明显的影响。
- tl;dr 答案从这里开始 -
经过一些黑客攻击,我们想出了如何强制 MVC 仅使用白名单命名空间内的控制器。
将“Default”路由上 DataTokens 字典的“UseNamespaceFallback”键设置为 false。现在,当我们请求“http://website/Abstract”时,“默认”路由仍然会匹配(这是有效的行为!)但 MVC 将不会使用任何不在定义的命名空间内的控制器;在这种情况下,只有“Web.Controllers”命名空间内的控制器才有效。最后,这就是我们正在寻找的功能!我们无法弄清楚为什么这不是默认行为。很奇怪吧?
希望这有帮助。
My friend and I were experiencing the same issue with Areas in ASP.NET MVC 2. We found a "hack" that, so far, seems to be working. For the tl;dr version, see the bottom of this answer.
You've probably got something similar to the following in your "Admin" area's "AdminAreaRegistration.cs" class:
Thus, it should make sense that when you make a request for "http://website/Abstract", the "Admin_default" route does not match the request. So, by design, the MVC framework attempts to match the request against any other defined routes. If you used the MVC tooling within Visual Studio to create your web project, you'll have a "Default" route defined in your "Global.asax" file (at the root of your web project). It should look similar to this:
The "Default" route succeeds in matching the request for "http://website/Abstract", with "controller" = "Abstract", "action" = "Index" (default value), and "id" = UrlParameter.Optional (default value). This is the correct, and intended, behavior... so far.
Now, the MVC framework will attempt to load the "Abstract" Controller. By design, MVC will search for a class called "AbstractController" that extends "Controller" anywhere within the web project's file/namespace hierarchy. It is important to note that a Controller's file location and namespace do not affect MVC's ability to find it; in other words, just because you've placed the "AbstractController" within a folder called "Areas\Admin\Controllers" and changed the namespace to be "Web.Areas.Admin.Controllers" instead of, say, "Web.Controllers", doesn't mean that MVC won't use it.
When MVC executes the "Index" action in "AbstractController" which, most likely, just returns "View()", then MVC gets confused because it doesn't know where to find the "Index" view. Because MVC has matched a non-area route (the "Default" route in Global.asax), it thinks the matching view should be located in non-area view folders. Thus you get the familiar error message:
We, just as you, didn't want requests for "http://website/Abstract" to resolve to "Admin" area's "AbstractController"; only "http://website/Admin/Abstract" should work. I can't think of why anyone would want this behavior.
A simple solution is to delete the "Default" route in Global.asax, but this will break any regular non-area Controllers/Views. This is probably not an option for most people...
So, we thought we could restrict the set of Controllers that MVC would use for requests matched by the "Default" route in Global.asax:
Nope. A request for "http://website/Abstract" will still use "AbstractController" within the "Admin" area, even though the "AbstractController"'s namespace is "Web.Areas.Admin.Controllers" and (clearly) not "Web.Controllers". This is thoroughly confusing; it seems like this white-list has no dicernable affect on MVC's Controller resolution.
- tl;dr answer starts here -
After some hacking, we figured out how to force MVC to only use Controllers within the white-listed namespace(s).
Set the "UseNamespaceFallback" key of the DataTokens dictionary on the "Default" route to false. Now, when we make a request for "http://website/Abstract", the "Default" route will still be matched (this is valid behavior!) but MVC will not use any Controller that is not within the defined namespace(s); in this case, only Controllers within the "Web.Controllers" namespace are valid. Finally, this is the functionality we were looking for! We can't figure out why this isn't the default behavior. Weird, huh?
Hope this helps.
您的路由设置正确吗?当您使用区域时,您必须手动更改路由代码,以便 MVC 查找正确的名称空间。
http://haacked.com/archive/2010/01/ 12/ambiguously-controller-names.aspx
Did you setup your routing correctly? When you use areas you have to manually change your routing code so that MVC looks in the right namespaces.
http://haacked.com/archive/2010/01/12/ambiguous-controller-names.aspx