1

I am wondering if there is any way of preventing an asp.net mvc controller from being executed, using an attribute if a particular criteria is not met when the controller was called?

What am basically trying to accomplish is to create something like an action filter but this time for a controller that is called before the controller is initialized and only if the filter succeeds before it is constructed, if not the attribute filter should be able to redirect the user to another controller.

Cizaphil
  • 490
  • 1
  • 6
  • 23
  • can you do it in the constructor instead? – Anonymous Duck Mar 17 '16 at 02:02
  • 1
    This smells a bit like an X-Y Problem. Why do you care if the controller is constructed unless you are doing way too much in the constructor? – DavidG Mar 17 '16 at 02:04
  • What am trying to is before constructing the controller, check if the part of the application is configured/enabled then either go ahead or redirect the user depending on the result. In essence I do not want to bother initializing a controller if there is no need for it – Cizaphil Mar 17 '16 at 02:07
  • You can define your custom atrribute filters in this case – Rajshekar Reddy Mar 17 '16 at 03:41
  • If I understand your question correctly. You're saying that the Controllers is being constructed even if it is not needed or being Instantiated anywhere in your code? Wow, that is new to me. – Aizen Mar 17 '16 at 05:03
  • No @Aizen that's not what am saying. What am saying in essence is how prevent a controller action method from executing when its called by the browser, but I was thinking whether its possible to do this in the controller level. That is create something like an attribute. – Cizaphil Mar 17 '16 at 17:48

1 Answers1

2

If you want to change controllers dynamically, the place to do it is in a custom RouteBase subclass. Redirection is a bad idea because your server will issue a 301 or 302 to the client's browser telling it to lookup a new location on the server. That round-trip is wasteful and unnecessary.

public class SwitcherRoute : RouteBase
{
    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        RouteData result = null;

        // Trim the leading slash
        var path = httpContext.Request.Path.Substring(1);

        // Check that the request is what you are interested in
        if (path.Equals("home/about", StringComparison.OrdinalIgnoreCase))
        {
            result = new RouteData(this, new MvcRouteHandler());


            if (/* some (preferably cached) condition */)
            {
                result.Values["controller"] = "Home";
                result.Values["action"] = "About";
            } 
            else 
            {
                result.Values["controller"] = "Alternate";
                result.Values["action"] = "About";
            }
        }

        // IMPORTANT: Always return null if there is no match.
        // This tells .NET routing to check the next route that is registered.
        return result;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        VirtualPathData result = null;

        var controller = Convert.ToString(values["controller"]);
        var action = Convert.ToString(values["action"]);

        if (action.Equals("About", StringComparison.OrdinalIgnoreCase))
        {
            if (controller.Equals("Home", StringComparison.OrdinalIgnoreCase) || 
                controller.Equals("Alternate", StringComparison.OrdinalIgnoreCase))
            {
                return new VirtualPathData(this, "home/about");
            }
        }

        // IMPORTANT: Always return null if there is no match.
        // This tells .NET routing to check the next route that is registered.
        return result;
    }
}

Usage

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

routes.Add(
    name: "AboutPage", 
    item: new SwitcherRoute());

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

Note that you can make your custom route more flexible by accepting constructor parameters or even inheriting from the built-in Route class.

Also note that routes run on every request, so you should cache any expensive lookup operations as in this example.

Community
  • 1
  • 1
NightOwl888
  • 55,572
  • 24
  • 139
  • 212