Search code examples
asp.net-mvcurl-routingasp.net-mvc-routingvalue-provider

MVC Routing Parameter Precedence


I came across a scenario where I had the default MVC Route setup. Like So.

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

Then navigating to a url as such

domain/controller/action/1234

On this page I was then navigating to the same page but with different parameters after a certain event. Like so.

    var id = $(this).data("id");
    var url = "@Url.Action("action", "controller", new { area = ""})";
    var params = $.param({id: id, vrnsearch: true});
    var fullUrl = url += "?" + params;

    window.location.href = fullUrl;

I noticed that the url was still keeping the same id in the url and attaching parameters like so.

domain/controller/action/1234?id=4321&vrnsearch=true

Now my question is, is there a way to determine a precedence over if it should use the value for id from the url or from the parameter.

I have actually found a work around/fix for my issue by using the below, which removes the id from the url and just uses parameters.

@Url.Action("action","controller", new {id = "", area = ""})

However was just curious if there is a precedence in parameters vs url routing.


Solution

  • The query string has nothing at all to do with routing (at least, not unless you customize routing to consider it).

    The values that are passed to the ModelBinder and to your action method are done so by Value Providers. You can control the order of precedence by changing the order in which their corresponding ValueProviderFactory is registered in the static ValueProviderFactories.Factories property.

    enter image description here

    As you can see, the default configuration is to first use the RouteDataValueProviderFactory and if it returns no value it will try the QueryStringValueProviderFactory. If you change the order of the factories, the order of precedence changes.

    ValueProviderFactories.Factories.RemoveAt(3);
    ValueProviderFactories.Factories.Insert(4, new RouteDataValueProviderFactory());