In a nutshell, a query string will not be part of the RouteData dictionary in the routing process, yet it will affect the route matching. On the other hand, when Model Binding takes place, query string will be used to bind to the parameters of the action method, unless there is an item in route data with the same key.
Now the details. Let us consider this ASP.NET MVC application. We have an action method:
public ViewResult Archive(DateTime? dateFrom, int? page)
{
...
}
And we have defined the following route:
routes.MapRoute(
"Archive",
"Archive/{dateFrom}",
new { controller = "Episode", action = "Archive", dateFrom = UrlParameter.Optional }
);
Let us check the URL ~/Archive/1-2-2012?page=2.
The RouteData dictionary will be as follows:
| Key | Value |
|---|---|
| controller | Episode |
| action | Archive |
| dateFrom | 1-2-2012?page=2 |
Yet the action method above will work, and be invoked with the parameters:
| Parameter | Value |
|---|---|
| dateFrom | 1-2-2012 |
| page | 2 |
So notice the following:
- The query string “page” key is NOT part of the RouteData dictionary.
- In the routing process, “?page=2” is considered to be part of the value of the “dateFrom” item in the RouteData dictionary (watch out for route unit tests).
- Even though “dateFrom” route item has the value “1-2-2012?page=2”, Model Binding figures out that it can ignore the “?page=2” part because it is a query string, and the
dateFromparameter is bound correctly to “1-2-2012”. - Even though there is NO “page” item in the RouteData dictionary, the query string is still used in Model Binding to bind to the
pageparameter.
Having this explained and the above notes in mind, what if we define an item named “page” in the route itself, like this:
routes.MapRoute(
"Archive",
"Archive/{dateFrom}",
new { controller = "Episode", action = "Archive", dateFrom = UrlParameter.Optional, page = 1 }
);
Then this item “page” will show in RouteData, but it should NOT be mistaken for the query string “page”. Model Binding will ignore the query string and use the route data item to bind to the action parameter page.
And this is why I am writing this post:
- I mistook the route item “page” for the query string “page” and this confused me a lot.
- My routing unit tests failed because the query string was still concatenated and present in the value of the route data item, which I should have ignored.
I hope this helps you better understand how query strings affect Routing and Model Binding, and helps you avoid what I went through. Watch out for routing unit tests, and good luck.