0

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&param1=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.

L. Kh
  • 13
  • 3
  • Only the last parameter can be optional (unless you provide all parameters, then there is no way for the routing engine to determine which value belongs to which segment so the values are added as query string values) –  May 30 '16 at 09:50
  • No, not only one last parametr may be optional. All parametrs may by optional in my case. I may write localhost:9285/hottours/tailand/bangkok/price_from_50000 or localhost:9285/hottours/tailand/bangkok/price_from_50000/from_moscow And all work is right. Untill i am not writing more than 6 variables in route rule. When i add more then 6 variables in route rule, urlHelper build url wrong – L. Kh May 30 '16 at 10:37
  • No, you not understanding Only the **last parameter** in a route definition can be marked with `UrlParameter.Optional`. If you attempt to use `Url.Action()` it will generate query string values (not route values) if you do not provide all parameters. Remove `countryTo = UrlParameter.Optional, ...... param4 = UrlParameter.Optional,` and leave only `param5 = UrlParameter.Optional` –  May 30 '16 at 10:42
  • But why all work is right, when i write url localhost:9285/hottours/tailand/bangkok/price_from_50000 and localhost:9285/hottours/tailand/bangkok/price_from_50000/from_moscow and localhost:9285/hottours/tailand/bangkok/ ? And UrlHelper build url absolutely right, when i give 2, 3, .. 6 params in RouteValueDictionary – L. Kh May 30 '16 at 10:51
  • It wont unless the parameters are added exactly in order - try `string url = urlHelper.Action("Index", "HotTours", new { param3 = "xxxx");` to understand. But you route only has 7 segments, so anything extra has to be a query string value –  May 30 '16 at 11:00
  • "unless the parameters are added exactly in order" > yes, of course. But in my case in url ALWAYS this: http://localhost:9285/hottours/tailand/bangkok/price_from_50000/ And if in route rule count of segments is less 6, all is ok – L. Kh May 30 '16 at 11:31

2 Answers2

1

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.

NightOwl888
  • 55,572
  • 24
  • 139
  • 212
  • ok, i understood and I will do all these rules, but explain me, please, if only one param may be UrlParameter.Optional, how with my previuos rule work next: http://localhost:9285/hottours/tailand/bangkok/price_from_50000/ http://localhost:9285/hottours/tailand/bangkok/price_from_50000/from_moscow ? – L. Kh May 30 '16 at 11:44
  • In my above example, both of these URLs will match (and be generated from) `HotToursPage2` since the last parameter `{param3}` is optional. They won't match `HotToursPage3` because `{param4}` is missing, so the routing engine will try the next route in the list until a match is found. – NightOwl888 May 30 '16 at 11:51
-1

Nothing like that as you are mentioning below is the main reason

Http.sys service is coded with default maximum of 260 characters per Url segment.

An "Url segment" in this context is the content between "/" characters in the Url. For example:

The max allowed Url segment length can be changed with registry settings:

Key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\HTTP\Parameters
Value: UrlSegmentMaxLength
Type: REG_DWORD
Data: (Your desired new Url segment maximum allowed length, e.g. 4096)

The maximum allowed value is 32766. If a larger value is specified, it will be ignored.

Restarting the PC is required to make a change to this setting take effect.

stylishCoder
  • 385
  • 1
  • 19
  • Thank you for your replay, but my situation is not related with length of segment. My url is always: http://localhost:9285/hottours/tailand/bangkok/price_from_50000 I don't change it. Params2... params5 are described only in RouteConfig When i add more then 6 variables in route rule , urlHelper build url wrong – L. Kh May 30 '16 at 10:28