I admit it. System.Uri (from the .NET Framework) has had me fooled for a long time. Normally when I need to extract the string value of a Uri instance, I use the AbsoluteUri method to do that. But that doesn’t work when the Uri instance models a relative URI. Indeed support for relative URI in the Uri class is almost nonexistant (makes me wish for a derived class called HttpUri that *would* allow you to work with relative URI, but that’s a topic for another day).
So the quick and dirty fallback I took when I wasn’t sure what type of Uri I had was to call ToString() to get the value of the URI (typically to pass to Response.Redirect, which sadly doesn’t use the Uri class, but expects a string). And this works just dandy until you get a Uri that has escaped characters in it that need to stay escaped for things to work properly (the example that killed me was ReturnUrl for Forms auth in ASP.NET).
The problem with carelessly using Uri.ToString is that it unescapes the URI before returning it.
That bears repeating, in bold.
Uri.ToString unescapes the URI before returning it.
The documentation for this method clearly states that this happens. But if you’re not thinking about escaped characters when you write your code, you’re not going to notice that anything’s wrong until it actually encounters certain escape sequences (in my case, the ReturnUrl was being truncated after an escaped ampersand got unescaped by Uri.ToString).
This can be really confusing while debugging…
…when for example, you hover your mouse over a variable of type System.Uri in the debugger. Because the debugger calls ToString() to get a string to display (at least I assume this is what’s happening, because if you set a watch on a System.Uri object, what you see will be different than if you watched its OriginalString or AbsoluteUri property instead, if there are escaped chars in the URI). This fooled me for a long time. But no longer! Now I know to take what the debugger shows for a Uri object with a grain of salt.
Unless you *really* want to unescape the URI, when writing code that uses the System.Uri class, I’d recommend using Uri.OriginalString instead of ToString to get the value of a Uri that may be absolute or relative. That will *not* unescape the string, and it’s one of the few properties on the Uri class that don’t throw an InvalidOperationException for a relative URI.
Here are my new personal rules that I’m going to use when using the System.Uri class:
Use Uri.AbsoluteUri to get the value of a URI when you know it’s absolute.
Use Uri.OriginalString to get the value of a URI when it could be either absolute or relative.
Use Uri.ToString to get the value of a URI only when you really want it to be unescaped (e.g. when you want to display it nicely for a human).
I hope this saves you a headache like the one I’ve had trying to track down the silly bug that this caused in our website.
Posted
Oct 10 2009, 11:04 AM
by
keith-brown