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’s consider this ASP.NET MVC application, we have an action method:
public ViewResult Archive(DateTime? dateFrom, int? page){...
And we have defined the following routes:
routes.MapRoute(
"Archive",
"Archive/{dateFrom}",
new { controller = "Episode", action = "Archive", dateFrom = UrlParameter.Optional}
);
Let’s check the URL “~/Archive/1-2-2012?page=2”:
The RouteData dictionary will be as the following:
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 let’s 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 your route unit tests!)
- Even though “dateFrom” route item has the value “1-2-2012?page=2”, Model Binding figures that it can ignore the “?page=2” part because it’s a query string, and the dateFrom parameter is bound correctly to the “1-2-2012”
- Even though there is NO “page” item in the RouteData dictionary, the query string it is still used in the Model Binding to bind to the “page” parameter
Having this explained and the above notes taken in mind, what if we have defined an item “page” in the route itself at the end like the following:
routes.MapRoute(
"Archive",
"Archive/{dateFrom}",
new { controller = "Episode", action = "Archive", dateFrom = UrlParameter.Optional, page = 1}
);
Then this item “page” will show in the RouteData but it should NOT be mistaken by the query string “page”, the Model Binding will always 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 have mistaken the route item “page” with 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, I should have ignored them
I hope this helps you better understand how query strings affects Routing and Model Binding, and helps you avoid what I have went through. Watch out for routing unit tests, and good luck.
Very Very Interesting Topic.
Thank You Very Much
Thanks MJ, I hope it benefits 🙂