I have an encoding problem I can’t seem to get to grips with regarding a parameter on a route. Basically, it either never URL encodes or it double URL encodes. I just want it single-encoded!
Here’s the route I have registered:
routes.MapRoute("Scan", "Scan/{*url}", new { controller = "Scan", action = "Index" });
Now I have a controller action that redirects to that route. For simplicity’s sake, let’s say it looks like this:
var url = "troyhunt.com/search";
return RedirectToRoute("Scan", new { url });
The resulting URL is “Scan/troyhunt.com/search” – note that the forward slash after .com has not been escaped.
Now let’s try that again but apply URL encoding:
var url = HttpUtility.UrlEncode("troyhunt.com/search");
return RedirectToRoute("Scan", new { url });
This time the resulting URL is “Scan/troyhunt.com%252fsearch” – note that the forward slash has been double-encoded. If I set a breakpoint before the redirect I can see the UrlEncode method successfully encoding the forward slash into a %2f.
It appears that the redirect is encoding the “%” symbol but not the “/”. If I test with other characters typically escaped with URL encoding (?,=), the encoding is working just fine directly from the RedirectToRoute method. Could this be an issue with treating the slash as separating route segments therefore not escaping? Am I missing something else here?
Update: more info, commentary and workaround is discussed in To route or not to route, that is the question.
Looking into System.Web.Routing it looks like this is happening due to the fact that route values are not URL encoded using
HttpUtility.UrlEncode(value)but in fact, are “escaped” usingUri.EscapeUriString(value).The offending code is in
System.Web.Routing.ParsedRoute:This could be a by design decision (would have to ask the Microsoft folks about that), due to the fact that forward slashes are a fairly integral part of routes. If it is I find it a little strange as the documentation for
Uri.EscapeUriString()states that it’s main usage as:Following through the code that generates the route URL, it doesn’t seem to use the
Uriclass at all – the URL is constructed and returned in a string.If you passed this as a query string parameter, rather than as part of a specified route, it would be properly URL encoded (but would of course change the structure of your URL).