1

I'm using this route config :

   routes.MapRoute("Default23",
                "{category}",
                new { controller = "Product", action = "List", page = 1 }
            );

Here is the controller method :

 public ViewResult List(string category, int page = 1)
{
}

However , if I use :

http://localhost:44123/chess?page=2

Then I see that page=1 ( not 2 , as I expected):

enter image description here

BTw - if I change the route to :

 routes.MapRoute("Default23",
                "{category}",
                new { controller = "Product", action = "List"  }
            );

Then I do see the right value:

enter image description here

Why is it happening ? all I wanted is to set a default value if I don't set a value . Why does setting a default value , prevents reading the query string value ?

d11
  • 380
  • 1
  • 3
  • 11
  • 1
    Possible duplicate of [How do I route a URL with a querystring in ASP.NET MVC?](https://stackoverflow.com/questions/6941967/how-do-i-route-a-url-with-a-querystring-in-asp-net-mvc) – Hooman Bahreini Nov 10 '18 at 23:52
  • @Hooman, That is not what OP is asking - you might consider retracting the close vote –  Nov 11 '18 at 02:21
  • @StephenMuecke, thanks... I thought [this answer](https://stackoverflow.com/questions/6941967/how-do-i-route-a-url-with-a-querystring-in-asp-net-mvc/6942066#6942066) explains the problem... – Hooman Bahreini Nov 11 '18 at 02:28

1 Answers1

2

To explain the behavior, the 3rd argument of MapRoute is (my emphasis)

An object that contains default route values.

By specifying new { controller = "Product", action = "List", page = 1 } you are defining a route value for page (even though its not a segment in your url definition) and giving it a default value of 1.

Now when you navigate to ../chess?page=2 it matches your Default23 route, and the value of 'chess' is assigned to the {category} segment, but nothing is assigned to page because there is no segment for {page} (its a query string value).

When your List(string category, int page = 1) method is executed, the DefaultModelBinder evaluates values for binding in the following order

  1. Previously bound action parameters, when the action is a child action
  2. Form values
  3. JSON Request body (ajax calls)
  4. Route data
  5. Query string parameters
  6. Posted files

For a GET, 1, 2, 3 and 6 are not applicable, so the DefaultModelBinder first evaluates the Route data (RouteData.Values) and finds a value of "chess" for category (from the url). It also finds a value of "1" for page (because you defined a default value for it in the route definition).

At this point you have category="chess", page=1.

The DefaultModelBinder then evaluates the Query string parameters (Request.QueryString) and finds a value of "2" for page, but because page already has been set, its ignored. By default, the DefaultModelBinder binds the first match it finds and ignores all subsequent matches (unless binding to an IEnumerable property).

So at this point (the end of the binding process) you still have category="chess", page=1.

  • So what if I want specify it conditionally via QS and still have a default value ? – d11 Nov 11 '18 at 06:59
  • You have already defined a default in the `List()` method (i.e. `int page = 1`) so if you omit `page = 1` from the route definition navigate to `.../chess`, (i.e. no query string) then the value of `page` will be `page=1` –  Nov 11 '18 at 07:27