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
- Previously bound action parameters, when the action is a child
action
- Form values
- JSON Request body (ajax calls)
- Route data
- Query string parameters
- 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
.