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

发布于 2024-11-02 04:57:34 字数 1081 浏览 0 评论 0原文

我有一个 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" });

捕获所有正确捕获不匹配的路线。

因此 {site}/Invalid/Action/id/extra 通过 catch all 正确路由。

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

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

我在哪里可以发现并改变这种行为?

I have an MVC 2 application that should always give a 'nice' 404 page.

However currently I get a low level .Net one: "Server Error in '/sitename' Application..."

I have a base controller that has a NotFound action that will render the nice 404 page.

Missing actions are handled:

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

So a visit to {site}/ValidController/NotAnAction gets routed correctly.

However a visit to {site}/NotAController doesn't.

I have routes set up with a 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" });

The catch all correctly catches routes that don't match.

So {site}/Invalid/Action/id/extra is correctly routed via the catch all.

However {site}/Invalid gets picked up via the "MVC routes" route and ASP.Net goes looking for InvalidController, and throws a dumb exception when it doesn't find it.

I know that I can override this at the web.config level, but that just redirects to the page. I'd like to know when the route pattern matches but the controller is not a valid controller name.

Where can I catch and change this behaviour?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

记忆で 2024-11-09 04:57:34

我终于找到了这个问题的答案,尽管它仍然不理想。

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

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

这并不理想,它添加了一个点击应用程序启动,仍然感觉过于复杂,但确实达到了预期的效果。

I finally found the answer to this, though it's still not ideal.

You can restrict the controller names that are allowed to match a route using a regex, so if we assume the default implementation of the controller factory we can figure out all the possible class names that are supported:

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

This isn't ideal, it adds a hit on the application start and still feels far too complicated, but it does have the desired effect.

夏花。依旧 2024-11-09 04:57:34

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(或错误日志模块和处理程序< /a> Scott Hanselman 写了一篇关于它的“介绍性”文章,但 ELMAH 是现在可以作为 NuGet 包使用。

您可能想看看这个问题/答案,了解如何将它与 ASP.NET MVC 一起使用:如何让 ELMAH 与 ASP.NET MVC [HandleError] 属性一起使用?

Setting it up at web.config level does not "just redirect to the page". On an MVC app, you give it a "{controller/action}" url an it will actually call that action:

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

This will call the NotFound on the SystemController.

In your action you can then for instance get the value of HttpContext.Request.RawUrl to see what the faulty request was: "/system/notfound?aspxerrorpath=/Invalid". In this case I tried to go to the InvalidController.

A nice way to handle this things, by the way, is implementing ELMAH (or Error Logging Modules and Handlers. Scott Hanselman wrote an "introductory" post about it, but ELMAH is nowadays available as a NuGet package.

You might want to take a look at this question/ansers on how to use it with ASP.NET MVC: How to get ELMAH to work with ASP.NET MVC [HandleError] attribute?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文