使用MVC 5 RouteArea属性时,无法找到默认区域视图

我有一个有多个领域的MVC5项目。 我有一个默认区域(名为Default ),在其中有一个默认控制器(名为DefaultController )。 这可以在现场路线上访问。

 [RouteArea] public class DefaultController : Controller { [Route] public ActionResult Index() { return View("Index"); } } public static void RegisterRoutes(RouteCollection routes) { routes.LowercaseUrls = true; routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapMvcAttributeRoutes(); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Default", action = "Index", id = UrlParameter.Optional }, namespaces: new[] { "MyProject.Areas.Default.Controllers" } ); } 

控制器已正确加载,但无法找到视图(位于Areas/Default/Views/Default/Index.cshtml )。 为什么MVC没有找对地方?

 The view 'Index' or its master was not found or no view engine supports the searched locations. The following locations were searched: ~/Areas/Controllers/Views/Default/Index.aspx ~/Areas/Controllers/Views/Default/Index.ascx ~/Areas/Controllers/Views/Shared/Index.aspx ~/Areas/Controllers/Views/Shared/Index.ascx ~/Views/Default/Index.aspx ~/Views/Default/Index.ascx ~/Views/Shared/Index.aspx ~/Views/Shared/Index.ascx ~/Areas/Controllers/Views/Default/Index.cshtml ~/Areas/Controllers/Views/Default/Index.vbhtml ~/Areas/Controllers/Views/Shared/Index.cshtml ~/Areas/Controllers/Views/Shared/Index.vbhtml ~/Views/Default/Index.cshtml ~/Views/Default/Index.vbhtml ~/Views/Shared/Index.cshtml ~/Views/Shared/Index.vbhtml 

我看到两个选择:

  1. 获取显式并使用[RouteArea("Default", AreaPrefix = "")]指定areaName ,其中“Default”是您所在区域的名称,设置AreaPrefix = ""获取应用程序根目录中的区域。
  2. 更改控制器所在的命名空间,以便最后一部分与您所在区域的名称相匹配。

请注意,如果您的区域的前缀是根(“”),则需要非常明确地使用您的操作[Route("...")]属性,这样他们就不会贪婪地声明应用程序中的所有路径,并且让你在其他一系列原因中挠头。

背景

当应用RouteAreaAttribute而不提供areaName或者提供的areaName为null时,您可能会收到这个奇怪的错误,或者您的操作可能使用了错误的视图(例如,您为某些其他目的创建了~/Views/Shared/Index.cshtml )。

RouteAreaAttribute.AreaName文档很有帮助:

(AreaName属性)获取要为控制器中定义的所有路径设置的区域名称。 如果该值为null,则将尝试从目标控制器的命名空间推断区域名称。

通过将[RouteArea]应用于您的控制器, areaName默认为null,这会导致某些逻辑接管“将从目标控制器的命名空间中推断出区域名称”。 显然推断涉及抓取命名空间的最后部分,传统上该部分是“控制器”,因为MVC开发人员已经被教导在Controllers文件夹中创建他们的控制器,并且默认情况下Visual Studio根据文件夹结构确定C#类的命名空间。

为了certificate我的观点,你可以将DefaultController的命名空间从MyProject.Areas.Default.Controllers更改为MyProject.Areas.Default ,切断“.Controllers”。 如果您重建并访问该操作,它将在“Areas / Default”文件夹下查找我们所期望的视图:

 ~/Areas/Default/Views/Default/Index.aspx ~/Areas/Default/Views/Default/Index.ascx ... 

而不是像“区域/控制器”文件夹那样没有人期望:

 ~/Areas/Controllers/Views/Default/Index.aspx ~/Areas/Controllers/Views/Default/Index.ascx ... 

我明白为什么开发人员选择这样做,但不幸的是他们忽略了我们如何教会组织ASP.NET MVC代码以及Visual Studio如何为项目添加区域和控制器。 这不是一个错误,而是一个比这更微妙和令人沮丧的东西。

这里可能存在许多问题。 当您声明一个区域时,第一个关闭的是一个单独的文件,其中包含到该区域的路径。 您需要查找DefaultAreaRegistration.cs文件(应该在您的Regions / Default文件夹中)并检查那里的区域路径。 它应该是这样的:

 context.MapRoute( "Default_default", "Default/{controller}/{action}/{id}", new { action = "Index", id = UrlParameter.Optional } ); 

注意这里的两件事。 区域路径中有一个明确的参考 – 默认/ {控制器} …这就是MVC知道你在这个名为Default的案例区域中的特定区域的目标。 要注意的第二件事是路由的名称是Default_default。 原因是站点默认路由也称为DEFAULT。 查看RouteConfig.cs文件,您将看到路由的名称是默认的。 因此,如果您明确指出两条路线相同,它们将相互覆盖。

我怀疑这两件事中有一件是你问题的原因……