Roger K Roger K - 1 month ago 15
JSON Question

Sending a json serialized object containing a escaped string using HttpWebRequest on mono

The requirement serialize a class and send it to the server.

Dev environment:

MonoDevelop 3.0.6

Runtime:
Mono 2.10.9 (tarball)

GTK 2.24.10

GTK# (2.12.0.0)


Operating System:

Mac OS X 10.7.4


The class contains a string with an escaped double quote in it.

class CustomClass
{
public string foo = "hi!\"";
}


The issue is that when I serialize it, encode it and create a URI object, the backslash used to escape double quote in the variable foo is converted into a forward slash, thus breaking the json.

Below are values of the different variables of the URI instance

Uri:
http://myserver/hello_world/0/{"foo":"hi!/""}

AbsoluteUri:
http://myserver/hello_world/0/%7B%22foo%22%3A%22hi%21/%22%22%7D

OriginalString:
http://myserver/hello_world/0/%7B%22foo%22%3A%22hi%21%5C%22%22%7D


The HttpWebRequest send the value
"http://myserver/hello_world/0/{"foo":"hi!/""}"
to the server, but for my requirement it should use the OriginalString to get a valid response from the server.

If i test the code on .NET the OriginalString is being sent to the server by the HttpWebRequest class, but there is additional code (hack) which doesn't work on mono mac

string paq = requestUri.PathAndQuery;
FieldInfo flagsFieldInfo = typeof(Uri).GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
ulong flags = (ulong)flagsFieldInfo.GetValue(requestUri);
flags &= ~((ulong)0x30); // Flags.PathNotCanonical|Flags.QueryNotCanonical
flagsFieldInfo.SetValue(requestUri, flags);


The code :

object messageObject = new CustomClass();

//try 1
//string jsonString = Uri.EscapeUriString(JsonConvert.SerializeObject(message2));

//try 2
//string jsonString = Uri.EscapeDataString(JsonConvert.SerializeObject(message2));

//try 3

string jsonString = System.Web.HttpUtility.UrlEncode(JsonConvert.SerializeObject(messageObject));

Uri uri = new Uri(string.Format("http://myserver/hello_world/0/{0}", jsonString));

//try 4:
//HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri.AbsoluteUri);

//try 5
//HttpWebRequest request =(HttpWebRequest)WebRequest.Create(string.Format("http://myserver/hello_world/0/{0}",jsonString));

//try 6
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri.OriginalString);

try
{
using (HttpWebResponse resp = request.GetResponse() as HttpWebResponse)
{
var reader = new StreamReader(resp.GetResponseStream());
string jsonResponse = reader.ReadToEnd();
}
}
catch (WebException wex)
{
Debug.WriteLine(wex.ToString());
}


As you can see I have tried using Uri.EscapeUriString, Uri.EscapeDataString and System.Web.HttpUtility.UrlEncode and using the AbsouluteUri and OriginalString to create the WebRequest instance and also creating it using a string.

I have also tried using the following code in the config.

<uri>
<schemeSettings>
<clear/>
<add name="http" genericUriParserOptions="DontUnescapePathDotsAndSlashes"/>
</schemeSettings>
</uri>


But none of the methods work and the encoding is lost when the request in created.

Any ideas to get this to work will be appreciated.

Update:

I have tried a lot of things including testing with some 3rd party open source code, but still faced the same issue when sending in an encoded url.

I modified the code to use WebClient instead of WebRequest but still no luck.

So the solution that worked for me on both MonoMac an MonoTouch(simulator, i haven't tested it on the device) was to create the request using TcpClient.

using (TcpClient tc = new TcpClient()) {
tc.Connect ("myserver", 80);

using (NetworkStream ns = tc.GetStream()) {
using (System.IO.StreamWriter sw = new System.IO.StreamWriter(ns)) {
using (System.IO.StreamReader sr = new System.IO.StreamReader(ns)) {
sw.Write("GET /hello_world/0/%7B%22foo%22:%22hi!%5C%22%22%7D HTTP/1.1 Host:myserver \r\n\r\n");
sw.Flush ();
string line;
while ((line=sr.ReadLine())!=null)
Console.Write (line);
}
}
}
}

Answer

I have tried a lot of things including testing with some 3rd party open source code, but still faced the same issue when sending in an encoded url.

I modified the code to use WebClient instead of WebRequest but still no luck.

So the solution that worked for me on both MonoMac an MonoTouch(simulator, i haven't tested it on the device) was to create the request using TcpClient.

using (TcpClient tc = new TcpClient()) {
tc.Connect ("myserver", 80);

using (NetworkStream ns = tc.GetStream()) {
    using (System.IO.StreamWriter sw = new System.IO.StreamWriter(ns)) {
        using (System.IO.StreamReader sr = new System.IO.StreamReader(ns)) {
            sw.Write("GET /hello_world/0/%7B%22foo%22:%22hi!%5C%22%22%7D HTTP/1.1 Host:myserver \r\n\r\n");
            sw.Flush ();
            string line;
            while ((line=sr.ReadLine())!=null)
                Console.Write (line);
            }
        }
    }
}
Comments