Since Silverlight 2 Beta 2 introduced the WebClient class, I decided to refactor an application we had by replacing all references to HttpWebRequest with the new client. Its methods seemed much more simple and clear, and I didn't even need to write a wrapper helper class to make calls to the server. But, as it happens with every refactor, I ran across a few problems.
The first thing I noticed was the fact that I the only method provided by the WebClient to send a stream of data in a POST to the server didn't return the server's response. The result parameter in the OpenWriteCompleted event is the opened writable stream, and I didn't find any way to obtain the server's response.
So, I ended up using the much simpler UploadString, which does return the response. The only problem is that I needed to serialize some objects, so I built an XmlWriter on top of a StringBuilder, serialized into it, and sent the ToString() of the writer:
XmlSerializer serializer = new XmlSerializer(typeof(T)); StringBuilder builder = new StringBuilder(); XmlWriter writer = XmlWriter.Create(builder); serializer.Serialize(writer, data); client.UploadStringAsync(url, builder.ToString());
But this threw an exception on the Java server, stating that it couldn't deserialize the POSTed object, because "Content is not allowed in prolog". Googling a few minutes it came up that encoding could be the cause, and seeing that the serializer generated UTF-16 code, I decided to go for UTF-8 and see what happened.
serializer.Serialize(writer, data, null, Encoding.UTF8.WebName);
Now came the big surprise. When I ran this code, I got a beautiful exception stating that I shouldn't set the encoding.
In other words, do not use the serialize method that sets encoding. The full text of the exception is The encoding style 'utf-8' is not valid for this call because this XmlSerializer instance does not support encoding. Use the SoapReflectionImporter to initialize an XmlSerializer that supports encoding.
Before you try to use the SoapReflectionImporter, let me tell you that it isn't included in the Silverlight 2 Beta 2 NET framework.
As a final attempt, I tried simply removing the xml document prolog. Since there isn't a XmlDocument class either in the framework, I had to do it the old way:
string written = builder.ToString(); written = written.Substring(written.IndexOf('>') + 1, written.Length - written.IndexOf('>') - 1);
And it worked. It seems that the WebClient was adding an extra header to the xml string I was sending, and therefore the Java web service threw the exception. Whatever the reason, it now works beautifully.
Update: Juan Wajerman pointed out that it is possible to pass XmlWriterSettings to its constructor, and specify there both the encoding and a very useful property named OmitXmlDeclaration, which does exactly what I wanted without needing to rely on the horrible string operations.
XmlSerializer serializer = new XmlSerializer(typeof(T)); StringBuilder builder = new StringBuilder(); using (XmlWriter writer = XmlWriter.Create(builder, new XmlWriterSettings { OmitXmlDeclaration = true })) { serializer.Serialize(writer, data); } string written = builder.ToString();