i've found the proper way to return XML to a client in ASP.NET. i think if i point out the wrong ways, it will make the right way more understandable.
Incorrect:
Response.Write(doc.ToString());
Incorrect:
Response.Write(doc.InnerXml);
Incorrect:
Response.ContentType = "text/xml";
Response.ContentEncoding = System.Text.Encoding.UTF8;
doc.Save(Response.OutputStream);
Correct:
Response.ContentType = "text/xml"; //must be 'text/xml'
Response.ContentEncoding = System.Text.Encoding.UTF8; //we'd like UTF-8
doc.Save(Response.Output); //save to the text-writer
//using the encoding of the text-writer
//(which comes from response.contentEncoding)
Use a TextWriter
Do use Response.Output
Do not use Response.OutputStream
Both are streams, but Output
is a TextWriter. When an XmlDocument
saves itself to a TextWriter, it will use the encoding specified by that TextWriter. The XmlDocument will automatically change the xml declaration node to match the encoding used by the TextWriter. e.g. in this case the xml declaration node:
<?xml version="1.0" encoding="ISO-8859-1"?>
would become
<?xml version="1.0" encoding="UTF-8"?>
This is because the TextWriter has been set to UTF-8. (more on this in a moment). As the TextWriter is fed character data, it will encode it with the byte sequences appropriate for its set encoding.
Incorrect:
doc.Save(Response.OutputStream);
In this example the document is incorrectly saved to the OutputStream, which performs no encoding change, and may not match the response's content-encoding or the xml declaration node's specified encoding.
Correct
doc.Save(Response.Output);
The xml document is correctly saved to a TextWriter object, ensuring the encoding is properly handled.
Set Encoding
The encoding given to the client in the header:
Response.ContentEncoding = ...
must match the xml document's encoding:
<?xml version="1.0" encoding="..."?>
must match the actual encoding present in the byte sequences sent to the client. To make all three of these things agree, set the single line:
Response.ContentEncoding = System.Text.Encoding.UTF8;
When the encoding is set on the Response object, it sets the same encoding on the TextWriter. The encoding set of the TextWriter causes the XmlDocument to change the xml declaration:
<?xml version="1.0" encoding="UTF-8"?>
when the document is Saved:
doc.Save(someTextWriter);
Save to the response Output
You do not want to save the document to a binary stream, or write a string:
Incorrect:
doc.Save(Response.OutputStream);
Here the xml is incorrectly saved to a binary stream. The final byte encoding sequence won't match the xml declaration, or the web-server response's content-encoding.
Incorrect:
Response.Write(doc.ToString());
Response.Write(doc.InnerXml);
Here the xml is incorrectly converted to string, which does not have an encoding. The xml declaration node is not updated to reflect the encoding of the response, and the response is not properly encoded to match the response's encoding. Also, storing the xml in an intermediate string wastes memory.
You don't want to Save the xml to a string, or stuff the xml into a string and response.Write a string, because that:
- doesn't follow the encoding specified
- doesn't set the xml declaration node to match
- wastes memory
Do use doc.Save(Response.Output);
Do not use doc.Save(Response.OutputStream);
Do not use Response.Write(doc.ToString());
Do not use 'Response.Write(doc.InnerXml);`
Set the content-type
The Response's ContentType must be set to `"text/xml"'. If not, the client will not know you are sending it xml.
Final Answer
Response.Clear(); //optional: if we've sent anything before
Response.ContentType = "text/xml"; //must be 'text/xml'
Response.ContentEncoding = System.Text.Encoding.UTF8; //we'd like UTF-8
doc.Save(Response.Output); //save to the text-writer
//using the encoding of the text-writer
//(which comes from response.contentEncoding)
Response.End(); //optional: will end processing