ASP.NET MVC-捕获所有路由和默认路由


72

为了使我的应用程序正确产生404错误,我在路由表的末尾实现了一条捕获所有路由,如下所示:

 routes.MapRoute(
            "NotFound", _
           "{*url}", _
           New With {.controller = "Error", .action = "PageNotFound"} _
       )

但是,要使其正常工作,我必须删除默认路由:

{controller}/action/{id}

但是现在已经删除了默认设置,我的大多数操作链接都不再起作用,而我发现让它们再次起作用的唯一方法是为每个控制器/操作添加单独的路由。

有没有一种更简单的方法,而不是为每个控制器/动作添加路由?

如果用户尝试导航到未知路由,是否可以创建一个默认路由,该默认路由仍允许全部路由工作?


1
您为什么认为404无法正常工作?
quakkels

@quakkels,我和@Sean有同样的抱怨。ASP.NET会引发404,但随后会进行302重定向,因此其结果不是所涉及页面上的真正404。这是使用时customErrors
达斯汀·莱恩

2
IMO,如果我去domain.com/nopage那里的nopage不是有效的控制,应该有404
达斯汀·莱恩

4
完全同意,404 =找不到,无论它是否是物理文件
肖恩·泰勒

2
HTTP 404-“找不到请求的资源。” HTTP / REST都是关于资源的,并引出一个问题,什么是“文件”?
路加·普普利特

Answers:


109

使用路线限制

在您的情况下,您应该定义默认路由{controller}/{action}/{id}并对其施加约束。可能与控制器名称甚至动作有关。然后把它全部抓住,它应该工作正常。

因此,当有人请求失败约束的资源时,全部路由将与请求匹配。

所以。首先定义具有路由约束的默认路由,然后在其后捕获所有路由:

routes.MapRoute(
    "Default",
    "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = UrlParameter.Optional },
    new { controller = "Home|Settings|General|..." } // this is basically a regular expression
);
routes.MapRoute(
    "NotFound",
    "{*url}",
    new { controller = "Error", action = "PageNotFound" }
);

好点子。我以为,只有控制器名称匹配时,第一条路线才会匹配...谢谢!
AndreiRînea'15

@andreirinea不,路由图未检查任何类型。它仅检查当前请求的URL是否与映射匹配。每条路线检查的唯一内容是约束(如果存在)。
罗伯特·科里特尼克

16
您可以使用反射来构建控制器约束,从而避免每次添加新控制器时的维护负担。private static string GetAllControllersAsRegex() { var controllers = typeof(MvcApplication).Assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(Controller))); var controllerNames = controllers.Select(c => c.Name.Replace("Controller", "")); return string.Format("({0})", string.Join("|", controllerNames)); }
Blisco 2015年

1
这是对无法通过路由解决的网址实施404错误的正确方法。还是只是一种解决方法和更清洁的解决方案。我觉得很有趣,2015年您必须手动处理服务器应完成的工作。
f470071 2015年

1
@ f470071:您是对的。在正常情况下,Web服务器可以轻松处理此问题,但有时应用程序具有特定的约束,应允许任意资源查询。OP想要做的唯一奇怪的事情是处理他们应用程序中的错误,而他们可以使用常规的Web服务器功能来处理错误。我还将在最后省略所有路由的定义,只使用我的答案中概述的约束路由。
罗伯特·科里特尼克

22
//this catches all  requests
routes.MapRoute(
    "Error",
    "{*.}",
     new { controller = "PublicDisplay", action = "Error404" } 
);

在路由表的末尾添加此路由


5
当然可以满足所有要求。但是,如果您在默认路由之前声明它,它将覆盖默认路由,并且如果您在默认路由之后声明它,则不会被调用,因为默认路由会捕获请求。
Tobias

2
"{*.*}",在asp.net vb上为我工作的一个
包包

"{*.}"只是在没有扩展的情况下抓到我的路线。更改为"{*.*}"捕获所有路由,包括.aspx。
基思·西蒙斯

7

嗯,问题在于您的默认路由会捕获所有3个细分网址。这里的问题是,在确定谁将处理请求之前,路由会运行。因此,任何三段URL都将匹配默认路由,即使在没有控制器处理它的情况下最终终止时也是如此。

您可以做的一件事是在控制器上重写HandleMissingAction方法。您还应该使用标记来捕获所有404问题。


2

好吧,我发现没有很好的方法可以做到这一点。我已将的redirectMode属性设置customErrorsResponseRewrite

<customErrors mode="On" defaultRedirect="~/Shared/Error" redirectMode="ResponseRewrite">
    <error statusCode="404" redirect="~/Shared/PageNotFound"/>
</customErrors>

这给了我追捧的行为,但是没有显示格式化的页面。

就我而言,就SEO而言,这做得不好。但是,我感觉缺少一种解决方案,因为SO确实可以实现我想要实现的目标。该URL保留在失败的页面上,并引发404。在Firebug中检查stackoverflow.com/fail。


有趣的是,您应该说,当我第一次开始研究该问题时,我首先检查了SO是如何处理的。我可以为每个操作手动添加路线,但是随着时间的推移,这很难维护。我真的认为MS可以在此问题上提供更好的指导。
肖恩·泰勒

3
也许我们能很好地问杰夫,他会和我们分享吗?:)
肖恩·泰勒

经过大量研究,尝试了各种解决方案后,这个解决方案似乎对我来说还可以。stackoverflow.com/questions/619895/…–
肖恩·泰勒

1

我建议将此作为最易读的版本。您需要在RouteConfig.cs和一个名为ErrorController.cs的控制器中,其中包含一个操作'PageNotFound'。这可以返回一个视图。创建一个PageNotFound.cshtml,它将返回以响应404:

        routes.MapRoute(
            name:  "PageNotFound",
            url:  "{*url}",
            defaults: new { controller = "Error", action = "PageNotFound" }
        );

如何阅读:

name: "PageNotFound"

=使用任意名称'PageNotFound'创建一个新的路由模板

url:"{*url}"

=使用此模板来映射所有其他未处理的路线

defaults: new { controller = "Error", action = "PageNotFound" }

=定义错误路径将映射到的操作(错误控制器中的“ PageNotFound”操作方法)。这是必需的,因为输入错误的路径显然不会映射到任何操作方法



0

您最好在配置部分配置404错误文档,然后再恢复默认路由。

FWIW,我认为默认路由要求也有所延迟。


0

我的解决方案是2个步骤。

我最初通过将以下函数添加到我的Global.asax.cs文件中来解决此问题:

protected void Application_Error(Object sender, EventArgs e)

我在哪里尝试将Server.GetLastError()强制转换为HttpException,然后检查GetHttpCode。此解决方案的详细信息在这里:

ASP.NET MVC自定义错误处理Application_Error Global.asax?

这不是我获得代码的原始来源。但是,这仅捕获已经路由的404错误。就我而言,该网址是2级网址。

例如,这些URL将显示404页面:

www.site.com/blah

www.site.com/blah/blah

但是,www.site.com / blah / blah / blah只会说找不到该页面。在我所有其他路线之后添加所有路线的渔获解决了此问题:

routes.MapRoute(
            "NotFound",
            "{*url}",
            new { controller = "Errors", action = "Http404" }
        );

但是,NotFound路由似乎不路由具有文件扩展名的请求。当它们被不同的路线捕获时,它确实起作用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.