为缺少的ASP.Net MVC控制器更正404消息

时间:2011-04-18 11:04:44

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

我有一个MVC 2应用程序应始终提供一个“漂亮的”404页面。

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

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

处理缺失的行为:

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

因此,{site}/ValidController/NotAnAction访问权限会被正确路由。

但访问{site}/NotAController时却没有。

我设置了使用catch all设置的路线:

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通过catch all正确路由。

然而{site}/Invalid通过“MVC路由”路由被接收,ASP.Net寻找InvalidController,并在找不到它时抛出一个愚蠢的异常。

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

我可以在哪里捕获并更改此行为?

2 个答案:

答案 0 :(得分:5)

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

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

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

这不是理想的,它会增加应用程序的开始,但仍然感觉太复杂,但它确实具有预期的效果。

答案 1 :(得分:0)

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

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

这将调用NotFound上的SystemController

在您的操作中,您可以获取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包使用。

您可能想看看这个问题/ ansers如何在ASP.NET MVC中使用它:How to get ELMAH to work with ASP.NET MVC [HandleError] attribute?