Correct 404 message for a missing ASP.Net MVC controller

前端 未结 2 1402
遇见更好的自我
遇见更好的自我 2021-01-03 10:15

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\' Applicatio

相关标签:
2条回答
  • 2021-01-03 10:17

    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?

    0 讨论(0)
  • 2021-01-03 10:32

    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.

    0 讨论(0)
提交回复
热议问题