0

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?

NightOwl888
  • 55,572
  • 24
  • 139
  • 212
Kasparov92
  • 1,365
  • 4
  • 14
  • 39
  • Are you referring to using the URL with / instead of the query parameters (make sure to leave the controller part off of the name of the controller in the URL)? Something like www.domain.com/area1/my/myaction – Bobby Caldwell Jul 09 '16 at 18:33
  • I would like to remove the controller and action from the url itself and add it as query parameter – Kasparov92 Jul 09 '16 at 18:39
  • 1
    Possible duplicate of [How do I route a URL with a querystring in ASP.NET MVC?](http://stackoverflow.com/questions/6941967/how-do-i-route-a-url-with-a-querystring-in-asp-net-mvc) – mtaanquist Jul 09 '16 at 18:47
  • @MadsTaanquist no I dont want to change the way the route works, I want it the same but to access it by querystring and with 'domain/controller/action?parameters' ... I want it as follow: 'domain?paramters' such that the parameters will tell the controller and action – Kasparov92 Jul 09 '16 at 18:51
  • Could you show the code in your RouteConfig? – mtaanquist Jul 09 '16 at 18:54

1 Answers1

2

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.

NightOwl888
  • 55,572
  • 24
  • 139
  • 212
  • I See .. Thanks .. but I am wondering "built-in routing ignores query string values" why does it work when adding "area" parameter but not working while adding controller or action as parameters – Kasparov92 Jul 09 '16 at 19:01
  • 1
    Areas use `DataTokens` (meta-data) rather than `Values` (route values) in order to function. In other words, they are a different animal than non-Area routing, so they are implemented differently. Apparently, one of those differences is that they consider query string values (but I can't seem to find the place in the source where this happens). If you *only* want to use query string values to navigate around, you have to use a custom route similar to what I provided above, there is no way to do this with the built-in routing extensions. – NightOwl888 Jul 09 '16 at 19:16