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

风流意气都作罢 提交于 2019-12-03 09:06:11

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();
    }
}
Keith

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 :-)

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>
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!