【问题标题】:Correct 404 message for a missing ASP.Net MVC controller更正缺少 ASP.Net MVC 控制器的 404 消息
【发布时间】:2011-08-07 19:10:10
【问题描述】:

我有一个 MVC 2 应用程序,它应该总是提供一个“不错”的 404 页面。

但是目前我得到了一个低级别的 .Net:“'/sitename' 应用程序中的服务器错误...”

我有一个基本控制器,它有一个 NotFound 动作,可以呈现漂亮的 404 页面。

处理缺失的动作:

protected override void HandleUnknownAction(string actionName)
{
    this.NotFound(actionName).ExecuteResult(this.ControllerContext);
}

因此,对{site}/ValidController/NotAnAction 的访问被正确路由。

但是访问{site}/NotAController 不会。

我设置了一条包罗万象的路线:

routes.MapRoute(
    "MVC routes",
    "{controller}/{action}/{id}",
    new { action = "Index", id = UrlParameter.Optional });

routes.MapRoute(
    "Catch All", 
    "{*url}",
    new { controller = "System", action = "NotFound" });

catch all 正确捕获不匹配的路由。

所以{site}/Invalid/Action/id/extra 被正确地路由通过全部捕获。

但是{site}/Invalid 是通过“MVC 路由”路由获取的,并且 ASP.Net 去寻找InvalidController,并在找不到时抛出一个愚蠢的异常。

我知道我可以在web.config 级别覆盖它,但这只是重定向到页面。我想知道路由模式何时匹配但控制器不是有效的控制器名称。

我在哪里可以捕捉和改变这种行为?

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-2 routing asp.net-mvc-routing


    【解决方案1】:

    我终于找到了答案,虽然还不理想。

    您可以使用正则表达式限制允许匹配路由的控制器名称,因此如果我们假设控制器工厂的默认实现,我们可以找出所有可能支持的类名称:

    // build up a list of known controllers, so that we don't let users hit ones that don't exist
    var allMvcControllers = 
        from t in typeof(Global).Assembly.GetTypes()
        where t != null &&
            t.IsPublic &&
            !t.IsAbstract &&
            t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) &&
            typeof(IController).IsAssignableFrom(t)
        select t.Name.Substring(0, t.Name.Length - 10);
    
    // create a route constraint that requires the controller to be one of the reflected class names
    var controllerConstraint = new
    {
        controller = "(" + string.Join("|", allMvcControllers.ToArray()) + ")"
    };
    
    // default MVC route
    routes.MapRoute(
        "MVC",
        "{controller}/{action}/{id}",
        new { action = "Index", id = UrlParameter.Optional },
        controllerConstraint);
    
    // fall back route for unmatched patterns or invalid controller names
    routes.MapRoute(
        "Catch All", 
        "{*url}",
        new { controller = "System", action = "NotFound" });
    

    这并不理想,它增加了应用程序启动的影响,并且仍然感觉过于复杂,但它确实达到了预期的效果。

    【讨论】:

    • 也许您可以仅在 Application_Start 中填写 controllerConstraint 以解决性能较低的问题?
    • 这是在 Application_Start 上 - 作为 .Net MVC 应用程序的标准。
    • 哦,你是对的......我的项目还没有打开......也许另一种方法可能正在使用某些属性......我们有一些路由,与控制器名称不同,所以我们不会将所有控制器称为“直接”...
    【解决方案2】:

    web.config 级别设置它不会“只是重定向到页面”。在 MVC 应用程序上,您给它一个 "{controller/action}" url,它实际上会调用该操作:

    <customErrors mode="On" defaultRedirect="/system/problem"> 
        <error statusCode="404" redirect="/system/notfound" />
    </customErrors>
    

    这将在SystemController 上调用NotFound

    然后,在您的操作中,您可以获取 HttpContext.Request.RawUrl 的值以查看错误请求是什么:"/system/notfound?aspxerrorpath=/Invalid"。在这种情况下,我尝试转到InvalidController

    顺便说一句,处理这些事情的一个好方法是实现ELMAH (or Error Logging Modules and Handlers。 Scott Hanselman wrote an "introductory" post about it,但 ELMAH 现在以 NuGet 包的形式提供。

    您可能想看看这个关于如何将它与 ASP.NET MVC 一起使用的问题/答案:How to get ELMAH to work with ASP.NET MVC [HandleError] attribute?

    【讨论】:

    • 我不认为它在 MVC2 中这样做(它可能在 3 中) - 我每次都被重定向。该应用程序混合了 WebForms 和 MVC 页面,如果我明确设置 &lt;customErrors mode="On" redirectMode="ResponseRewrite"... 我会在两者之间出错。
    猜你喜欢
    • 2016-05-14
    • 2013-10-24
    • 1970-01-01
    • 2015-01-02
    • 1970-01-01
    • 1970-01-01
    • 2011-12-29
    • 2017-09-19
    • 2018-07-22
    相关资源
    最近更新 更多