【问题标题】:ASP.NET MVC4 Searching for controller in wrong areaASP.NET MVC4 在错误区域搜索控制器
【发布时间】:2013-06-20 21:48:02
【问题描述】:

我正在使用默认的 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。

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-3 asp.net-mvc-4


    【解决方案1】:

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

    Area 中的AreaRegistration 类中添加命名空间

    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

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

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

    RouteDebug.RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);
    

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



    图-2

    问题

    动作仍然被调用,虽然没有找到视图所以我得到一个错误。

    回答

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


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

    我创建了一个派生自ActionFilterAttribute 的类,如下所示。这仅包含一个名为OnResultExecutingOverride。这个Handler在执行特定Action对应的View之前执行

    创建这个类的目的只是为了验证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?

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

    为了检查这一点,我在Area内部Controller的Action Method中设置了调试器,发现当Requested url没有Area Name时,没有DataToken信息。让我们在Debug 模式中查看有关DataToken 的更多详细信息


    图-3

    如果你注意ControllerContext,我列举了DataTokens,它没有显示键/值。这是因为在Root Directory 下找不到与该控制器相关的视图

    你怎么能说当前所在的目录是根目录呢?证明如下




    图-4

    RouteData 值中没有提到命名空间或任何区域。对吧?

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

    匹配的 RouteData




    图-5

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

    如果出现上述请求的 URL,我对 DataTokens 的最终详细信息。这次可以看到 Namespace 详细信息和 Area 详细信息。


    图-6





    结论

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

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

    【讨论】:

    • 非常彻底!唯一缺少的是对 why 的简单解释 :) 干得不错。我投票赞成
    • 非常感谢您对此问题的详细解释。我遇到了类似的问题,非常感谢一个易于阅读的答案。
    【解决方案2】:

    检查一下。像这样修改 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

    【讨论】:

    • 抱歉,查询是如何执行区域中的控制器而不在Controller 名称之前输入Area Name
    • 您的解决方案解决了我的问题,既然您是会员,我将奖励您 25 分。 User2015869 - 你的解释胜过任何 MVC 书籍。
    • UseNamespaceFallback 帮我搞定了...仅指定命名空间是不够的...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-03
    • 2013-11-22
    • 1970-01-01
    相关资源
    最近更新 更多