Search code examples
asp.net-mvcasp.net-mvc-routing

ASP MVC - Access Controller/Action using parameter name


I am using ASP MVC4 and I would like to know if I can open a specific page as follow:

www.domain.com?Area=area1&controller=myController&Action=MyAction

instead of

www.domain.com/area1/mycontroller/MyAction

It works for me when I use the area as parameter but when I use the controller and action too as query parameters, it fails. Is there a way to make it work as Url parameters?


Solution

  • By default, the built-in routing ignores query string values (it does not add them to the RouteData.Values dictionary). However, there is no reason why you can't extend routing to consider them.

    public class QueryStringRoute : RouteBase
    {
        public RouteData GetRouteData(HttpContextBase httpContext)
        {
            var path = httpContext.Request.Path;
    
            if (!string.IsNullOrEmpty(path))
            {
                // Don't handle URLs that have a path /controller/action
                return null;
            }
    
            var queryString = httpContext.Request.QueryString;
    
            if (!queryString.HasKeys())
            {
                // Don't handle the route if there is no query string.
                return null;
            }
    
            if (!queryString.AllKeys.Contains("controller") && !queryString.AllKeys.Contains("action"))
            {
                // Don't handle the case where controller and action are missing.
                return null;
            }
    
            var controller = queryString["controller"];
            var action = queryString["action"];
            var area = queryString["area"];
    
            var routeData = new RouteData(this, new MvcRouteHandler());
    
            routeData.Values["controller"] = controller;
            routeData.Values["action"] = action;
            routeData.DataTokens["area"] = area;
    
            return routeData;
        }
    
        public VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
        {
            // NOTE: MVC automatically tacks unrecognized route values onto
            // the query string. So, it is sufficient to just call your 
            // ActionLink normally and returning an empty string for the URL
            // will send it to mysite.com/?controller=foo&action=bar
            return new VirtualPathData(this, string.Empty);
        }
    }
    

    Usage

    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
            // Add the query string route
            routes.Add(new new QueryStringRoute());
        }
    }
    

    I haven't tested this, so it may need some tweaking to get it to work right, but this is how you can do it.

    Do note however, this is bad for SEO and also you will need to add additional code to handle parameters other than controller, action, and area (such as id). You could pass values to match into the route constructor, and then register the QueryStringRoute class with different parameters in order to overcome this problem.