ASP.NET route with arbitrary number of key-value pairs – is it possible?

I’d like to handle URLs like this:

/Id/Key1/Value1/Key2/Value2/Key3/Value3/

Right now, I have set up a rule like this:

/{id}/{*parameters}

The parameters object is passed as a single string to all the actions that are involved in forming the response. This does work, but I have a few problems with it:

  1. Each action must resolve the string for itself. I’ve, of course, made an extension method that turns the string to a Dictionary<string, string>, but I’d prefer it if the dispatching mechanism gave my methods a Dictionary<string, string> directly – or, better yet, the actual pairs as separate arguments.
  2. Action links will still add parameters using the traditional format (?Key1=Value1). I guess I could write specialized helpers with my desired format, but I’d prefer it if there was a way to make the existing overloads follow the above routing rule.

Is there a way to do the above?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

You could write a custom route:

public class MyRoute : Route
{
    public MyRoute()
        : base(
            "{controller}/{action}/id/{*parameters}",
            new MvcRouteHandler()
        )
    {
    }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        var rd = base.GetRouteData(httpContext);
        if (rd == null)
        {
            return null;
        }

        string parameters = rd.GetRequiredString("parameters");
        IDictionary<string, string> parsedParameters = YourExtensionMethodThatYouAlreadyWrote(parameters);
        rd.Values["parameters"] = parsedParameters;
        return rd;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        object parameters;
        if (values.TryGetValue("parameters", out parameters))
        {
            var routeParameters = parameters as IDictionary<string, object>;
            if (routeParameters != null)
            {
                string result = string.Join(
                    "/", 
                    routeParameters.Select(x => string.Concat(x.Key, "/", x.Value))
                );
                values["parameters"] = result;
            }
        }
        return base.GetVirtualPath(requestContext, values);
    }
}

which could be registered like that:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.Add("my-route", new MyRoute());

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

and now your controller actions could take the following parameters:

public ActionResult SomeAction(IDictionary<string, string> parameters)
{
    ...
}

As far as generating links following this pattern is concerned, it’s as simple as:

@Html.RouteLink(
    "Go", 
    "my-route", 
    new {
        controller = "Foo",
        action = "Bar",
        parameters = new RouteValueDictionary(new { 
            key1 = "value1", 
            key2 = "value2",
        }) 
    }
)

or if you wanted a <form>:

@using (Html.BeginRouteForm("my-route", new { controller = "Foo", action = "Bar", parameters = new RouteValueDictionary(new { key1 = "value1", key2 = "value2" }) }))
{
    ...    
}

Method 2

Write your own model binder for a specialized dictionary. If you will have one there will be no need for parsing the string in each action method.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x