The urlHelper build wrong path.. What is a rison for this?

252 views Asked by At

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.

2

There are 2 answers

2
NightOwl888 On BEST ANSWER

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.

1
stylishCoder On

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.