I have a route rule as:
routes.MapRoute("HotToursPage",
"HotTours/{countryTo}/{resort}/{param1}/{param2}/{param3}/{param4}/{param5}",
new
{
controller = "HotTours",
action = "Index",
countryTo = UrlParameter.Optional,
resort = UrlParameter.Optional,
param1 = UrlParameter.Optional,
param2 = UrlParameter.Optional,
param3 = UrlParameter.Optional,
param4 = UrlParameter.Optional,
param5 = UrlParameter.Optional
}
);
In the code I have:
var dictionary = new RouteValueDictionary();
aaa.Add("countryTo", countryToInfo.Translit);
aaa.Add("resort", resort);
aaa.Add("param1", param1);
string url = urlHelper.Action("Index", "HotTours", dictionary);
If there are param5, param6 and other, then
url =/hottours/?countryTo=tailand&resort=bangkok¶m1=price_from_50000,
but if i remove param5, param6 and other, then all ok:
url =/hottours/tailand/bangkok/price_from_50000
Why if segment count is less then 7, all ok? I need 9 segments, but urlHelper builds wrong url in this case.
When building URLs, you have to provide all of the route values that are in the URL pattern. There is one exception - when the last parameter is optional, you don't need to include it.
Therefore, to consistently deal with segments that could be optional in a long URL pattern, you need more than one route. Each route can only have one UrlParameter.Optional
and it must be the right-most segment.
routes.MapRoute("HotToursPage3",
"HotTours/{countryTo}/{resort}/{param1}/{param2}/{param3}/{param4}/{param5}",
new
{
controller = "HotTours",
action = "Index",
param5 = UrlParameter.Optional
}
);
routes.MapRoute("HotToursPage2",
"HotTours/{countryTo}/{resort}/{param1}/{param2}/{param3}",
new
{
controller = "HotTours",
action = "Index",
param3 = UrlParameter.Optional
}
);
routes.MapRoute("HotToursPage1",
"HotTours/{countryTo}/{resort}/{param1}",
new
{
controller = "HotTours",
action = "Index",
param1 = UrlParameter.Optional
}
);
NOTE: I am assuming here that your
{countryTo}
and{resort}
parameters are required. It doesn't seem that sensible to make them optional. However, if I am mistaken, you need another route to deal with those 2 segments being optional or alternatively you should provide sensible default values for them. Generally speaking, if there are no sensible defaults for a value it should be required in the URL.
Do note that you still can only make a segment optional if none of the segments to the right of it are provided. Therefore, this combination will work:
var dictionary = new RouteValueDictionary();
dictionary.Add("countryTo", "test1");
dictionary.Add("resort", "test2");
dictionary.Add("param1", "test3");
var url = Url.Action("Index", "HotTours", dictionary);
But this combination will still build a query string:
var dictionary = new RouteValueDictionary();
dictionary.Add("countryTo", "test1");
dictionary.Add("resort", "test2");
dictionary.Add("param1", "test3");
dictionary.Add("param2", "test4");
dictionary.Add("param5", "test5");
var url = Url.Action("Index", "HotTours", dictionary);
If you want all 5 of your params to be optional (and in any order), you should use query strings, rather than putting them into the path.
routes.MapRoute("HotToursPage",
"HotTours/{countryTo}/{resort}",
new
{
controller = "HotTours",
action = "Index"
}
);
An alternative (that I don't recommend) would be to build up a series of routes that have identifier segments, which allows you to place the values in any order. See ASP.Net MVC Handling Segments with Route.