views:

207

answers:

3

I'm working on a client app that uses a restful service to look up companies by name. It's important that I'm able to include literal ampersands in my queries since this character is quite common in company names.

However whenever I pass %26 (the URI escaped ampersand character) to System.Uri, it converts it back to a regular ampersand character! On closer inspection, the only two characters that aren't converted back are hash (%23) and percent (%25).

Lets say I want to search for a company named "Pierce & Pierce":

var endPoint = "http://localhost/companies?where=Name eq '{0}'";
var name = "Pierce & Pierce";
Console.WriteLine(new Uri(string.Format(endPoint, name)));
Console.WriteLine(new Uri(string.Format(endPoint, name.Replace("&", "%26"))));
Console.WriteLine(new Uri(string.Format(endPoint, Uri.EscapeUriString(name))));
Console.WriteLine(new Uri(string.Format(endPoint, Uri.EscapeDataString(name))));

All four of the above combinations return:

http://localhost/companies?where=Name eq 'Pierce & Pierce'

This causes errors on the server side since the ampersand is (correctly) interpreted as a query arg delimiter. What I really need it to return is the original string:

http://localhost/companies?where=Name eq 'Pierce %26 Pierce'

How can I work around this behavior without discarding System.Uri entirely? I can't replace all ampersands with %26 at the last moment because there will usually be multiple query args involved and I don't want to destroy their delimiters.

Note: A similar problem was discussed in this question but I'm specifically referring to System.Uri.

+2  A: 

It's not only the ampersand that is incorrect in the URL. A valid URL can not contain spaces.

The EscapeDataString method works just fine to encode the string properly, and you should encode the entire value, not just the name:

Uri.EscapeDataString("Name eq 'Pierce & Pierce'")

Result:

Name%20eq%20'Pierce%20%26%20Pierce'

When you create an Uri using this string, it will be correct. To see the URL you can use the AbsoluteUri property. If you just convert the Uri to a string (which calls the ToString method) the URL will be unescaped and thus appear incorrect.

Guffa
Ah, now I get it. ToString() is an un-escaped human readable version of the uri.
Nathan Baulch
A: 

I encount the same problem. Though the query string is escaped with Uri.EscapeDataString, and the property AbsoluteUri do reprent it correctly, but WebBrowser send the Uri in unescaped format.

  currentUri = new System.Uri(ServerAgent.urlBase + "/MailRender?uid="
+ Uri.EscapeDataString(uid);

webBrowser.Navigate(currentUri);

Plus sign ('+') is convert to %2B, but the server still get + in URL, which is then convert to space (' ') via HttpServeletRequest.getParameter() call

Daniel
A: 

I have resolved this problem by create a derived class of Uri

    class Uri2 : System.Uri
{
    public Uri2(string url) : base(url)
    {
    }

    public override string ToString()
    {
        return AbsoluteUri;
    }
}

In any place System.Uri is used, use Uri2 replaced. I don't know whether this is a bug of .NetCF, WebBrowser should send URL in encoded format, i.e. the value of AbsoluteUri, but not value from ToString()

Daniel