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

时间:2013-06-20 21:48:02

标签: 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 }
        );

我将区域定义为:

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 }
            );
        }
    }

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

namespace XXX.Areas.Administration.Controllers
{
    public class CountryController : Controller
    {
        public ActionResult Index()
        {
///
        }
    }
}

当我输入

  

/管理/国家

它可以满足需要。

当我输入

  

/国家

动作仍然会被调用,但是找不到视图,所以我收到错误。

为什么MVC接受

  

/国家

作为有效路线?我在非地区没有其他CountryController。

2 个答案:

答案 0 :(得分: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" }
);

AreaRegistration

中的Area课程中添加NameSpace
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" }
        );
    }
}

<强>解释

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

图-1

enter image description here

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

在前往目的地之前。我将向您展示我如何初始化我的测试。我添加了 RoureDebugger. You can get the Dll from this location 的参考。然后我在Application_Start处理程序下的Global.asax文件中添加了一行代码。

RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);

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



图-2

enter image description here

<强>问题

  

动作仍然会被调用,但是找不到视图,所以我收到错误。

<强>答案

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


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

我创建了一个类,它来自ActionFilterAttribute,如下所示。这只包含一个Override,称为OnResultExecuting。此Handler在执行与特定View

对应的Action之前执行

创建此类的目的只是验证RouteDataDataTokens发生了什么。

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);
    }
}

确定。让我们回到最初的问题。为什么我会得到404?

在检查Controller之前,您的{controller}/{action}将被默认基本路由Area Route选中,因此会在View中查找Root/Views而不是Area/views

为了检查这一点,我在区域内的Controller方法中设置了调试器,发现当请​​求的URL没有DataToken时没有Area Name信息。我们在DataToken模式下查看有关Debug的更多详细信息


图-3

enter image description here

如果你关注ControllerContext,我列举了DataTokens,它没有显示任何键/值。这是因为在Root Directory

下没有找到与该控制器有关的视图

怎么说当前定位的目录是根目录?证明在下面




图-4

enter image description here

RouteData值中没有提到任何名称空间或任何区域。正确?

现在让我们转到匹配包含RouteData的模式的Area Name。所以,这次我的网址为:http://localhost:2474/mypractise/ActionFilterAttribute/index,而下方是 URLRoutingModule

匹配的RouteData




图-5

enter image description here

请注意突出显示的部分,这次Route匹配属于AreaName模式,默认路由的匹配值为false,属于根目录中的某些RouteData。正确?

在上述请求的网址的情况下,DataTokens的最终详细信息。您可以在此次查看命名空间详细信息和区域详细信息。


图-6

enter image description here



结论

Controller位于区域内且您的DataTokens未显示AreaNameSpaceUseNameSpaceFallback信息的信息时。这意味着您将获得404.如图4所示,您请求的Url是正确的,因此您获得了DataTokens并且如图3所示,DataTokens未显示,因为请求的Url不包含{{ 1}}尽管您已经获得了图2中提到的Area Name,但因为它是默认的Url模式。最后尝试在RouteData中执行第三行代码。它将显示null,因为找不到View。

希望这个解释对你有所帮助。

答案 1 :(得分: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;

编辑:

道歉。看起来你没有希望它这样做以及知道为什么

您遇到的问题是默认路由将查找任何控制器。即使它在一个区域。您只需将namespaces参数添加到路由中即可克服此默认行为,并指定控制器应查找的默认路由。

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

有一篇很好的文章说明为什么会发生here