Creating a Catch-All Route

2019-04-13 05:59发布

问题:

I've found several examples online (especially on StackOverflow) for creating a catch-all route in ASP.NET MVC, but this doesn't appear to be working for me in MVC4:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.IgnoreRoute("elfinder.connector");

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );

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

}

With the controller action defined as:

    public ActionResult CatchAll(string url)
    {
        // catch the URL and use it for something
    }

The goal here is to intercept all potential 404 errors and, depending on the URL, either respond with a 404 or with something else. However, I never end up in the CatchAll action, I just get a default 404 for URLs like:

  • ~/foo
  • ~/this/is/a/test/url

Am I doing something wrong here? I'd like to avoid having to catch the errors in Application_Error and, if it's a 404, re-forward from there. It just seems kind of messy. It seems to me that the proper way to handle these requests would be to simply route them to the correct action, no?

UPDATE: While the URL purist in me wants to avoid the use of Response.Redirect, I'm currently trying the following as a global catch-all for requests:

protected void Application_Error()
{
    Exception exception = Server.GetLastError();
    HttpException httpException = exception as HttpException;

    if (httpException != null)
        if (httpException.GetHttpCode() == 404)
        {
            Server.ClearError();
            Response.Redirect(String.Format("~/Home/CatchAll/?url={0}", Request.Path));
        }
}

However, this only works if the structure of the URL matches a route. Otherwise it looks like IIS doesn't even send the request to the application, it just returns a 404 directly. I need pretty much a global handler where any URL requested of the website which doesn't map to an action gets directed.

UPDATE: It looks like a combination of two things should do the trick for me. First, catching 404s in Application_Error (or Application_EndRequest as some people suggest, either way works for my needs) covers anything that matches a route structure but doesn't find an action. However, there's still the case of requests which don't match a route structure.

For varying reasons, I don't want to have to tweak IIS for this. The solution should be contained within the application itself. Luckily, I can guarantee the latest .NET and IIS, which allows me to use Web.config settings to instruct IIS on how to handle errors. So I'm currently trying this:

<httpErrors errorMode="Custom" defaultResponseMode="Redirect" defaultPath="/Home/CatchAll">
  <clear/>
</httpErrors>

However, this doesn't appear to be quite right. It is affecting IIS in that the error response has changed, but it's still an error response. Which is:

HTTP Error 500.19 - Internal Server Error

The requested page cannot be accessed because the related configuration data for the page is invalid.

So it looks like I'm on the right track, I'm just having a difficult time finding a working example of using httpErrors in the Web.config to send all 404s (or even all errors, it makes little difference for my needs) to an action.