ASP.NET MVC - Use Reflection to find if a Controller Exists

前端 未结 3 802
离开以前
离开以前 2021-02-10 04:23

I\'m having a heck of a time figuring out how to properly implement my 404 redirecting.

If I use the following

 _
Public Class BaseC         


        
相关标签:
3条回答
  • 2021-02-10 04:45

    I have a C# solution, I hope it helps. I plagiarized some of this code, though for the life of me, I cannot find where I got it from. If anyone know, please let me know so I can add it to my comments.

    This solution does not use reflection, but it looks at all the application errors (exceptions) and checks to see if it's a 404 error. If it is, then it just routes the current request to a different controller. Though I am not an expert in any way, I think this solution might be faster than reflection. Anyway, here's the solution and it goes into your Global.asax.cs,

        protected void Application_Error(object sender, EventArgs e)
        {
            Exception exception = Server.GetLastError();
    
            // A good location for any error logging, otherwise, do it inside of the error controller.
    
            Response.Clear();
            HttpException httpException = exception as HttpException;
            RouteData routeData = new RouteData();
            routeData.Values.Add("controller", "YourErrorController");
    
            if (httpException != null)
            {
                if (httpException.GetHttpCode() == 404)
                {
                    routeData.Values.Add("action", "YourErrorAction");
    
                    // We can pass the exception to the Action as well, something like
                    // routeData.Values.Add("error", exception);
    
                    // Clear the error, otherwise, we will always get the default error page.
                    Server.ClearError();
    
                    // Call the controller with the route
                    IController errorController = new ApplicationName.Controllers.YourErrorController();
                    errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
                }
            }
        }
    

    So the controller would be,

    public class YourErrorController : Controller
    {
        public ActionResult YourErrorAction()
        {
            return View();
        }
    }
    
    0 讨论(0)
  • 2021-02-10 04:46

    Why don't you just capture them with custom errors in your web.config file and avoid a bunch of reflection all together?

    <customErrors mode="On">   
        <error statusCode="404" redirect="/Error/NotFound" />
    </customErrors>
    
    0 讨论(0)
  • 2021-02-10 04:48

    That's a very similar problem to mine, but I like your alternate approach.

    I think the reflection as a dynamic filter might be too performance heavy, but I think I have a better way - you can filter allowed actions by a Regex:

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

    Then I add to this an additional method on my base Controller:

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

    In this case BaseController.NotFound handles the missing action on a valid controller.

    So finally:

    • {site}/invalid - found by new reflection based filter
    • {site}/valid/notAnAction - found by HandleUnknownAction
    • {site}/valid/action/id - found by checks in code for the id (as before)
    • {site}/valid/action/id/extraPath - found by not matching any route but the catch all

    I think that's all the 404 scenarios covered :-)

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