tags:

views:

2269

answers:

6
A: 

You've basically answered anything and everything already, so I'm no sure what the point is here?

FWIW I would use an httphandler - there seems no point in invoking a page lifecycle and having to deal with clipping off the bits of viewstate and session and what have you which don't make sense for an XML doc. It's like buying a car and stripping it for parts to make your motorbike.

And content-type is all important, it's how the requester knows what to do with the response.

annakata
Those various things i've posted came from the various solutions i've found posted on the internet. And here on SO we have two answer and two approaches.
Ian Boyd
"two"? not sure I understand
annakata
At the time i posted that comment there were two answers to this question, with two very different approaches. As of now (10:30am) there are three approaches. i was hoping everyone who posts "their" solution would also explain why the other solution is "wrong".
Ian Boyd
My point is, i should probably create a new question, "What is the best way to return XML in ASP.net", and post the 10 different solutions i've found on the internet, the 4 i have in my question, the 3 answers so far, and let people then focus on deciding the right way.
Ian Boyd
Great, another random downvote. Good job fella.
annakata
A: 

mate...

this is not a question! this is,

of all this cars in the stand, witch should I drive

type of a question.

There are literally MILLIONS of tutorials on how to write proper XML, to the browser, to a file, to the memory, etc etc etc ...

please see this website as a

I can't find a proper solution, might go to SO website, they will probably help me!

try to start with the most known tutorial on this planet... the 4 Guys From Rolla tutorial

balexandre
Except i wasn't asking about how to write XML. i was asking how to return XML to an HTTP client from an ASP.net web-server.
Ian Boyd
errr... so what's this: // Write XML using xmlWriter //TODO: How to do this?
balexandre
+3  A: 

Ideally you would use an ashx to send XML although I do allow code in an ASPX to intercept normal execution.

Response.Clear()

I don't use this if you not sure you've dumped anything in the response already the go find it and get rid of it.

Response.ContentType = "text/xml"

Definitely, a common client will not accept the content as XML without this content type present.

 Response.CharSet = "UTF-8";

Let the response class handle building the content type header properly. Use UTF-8 unless you have a really, really good reason not to.

Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetAllowResponseInBrowserHistory(true);

If you don't send cache headers some browsers (namely IE) will cache the response, subsequent requests will not necessarily come to the server. You also need to AllowResponseInBrowser if you want this to work over HTTPS (due to yet another bug in IE).

To send content of an XmlDocument simply use:-

dom.Save(Response.OutputStream);

Just be sure the encodings match, (another good reason to use UTF-8).

Response.End()

If you really have to in an ASPX but its a bit drastic, in an ASHX don't do it.

AnthonyWJones
Does anyone have to worry about including "<?xml version="1.0" encoding="utf-8"?>" The doc.Save doesn't seem to do it.
Ian Boyd
I don't worry about it I've not come across a parser that gets upset over its not being there. UTF-8 is the default.
AnthonyWJones
This example incorrectly uses `Response.OutputStream` (a Stream) rather than `Response.Output' (a TextWriter)
Ian Boyd
@Ian: Care to explain? Works fine in the zillion places that I use it. If you really feel the need to take more control you would be better off creating a proper XmlTextWriter over the OutputStream and giving that to Save.
AnthonyWJones
@Anthony: because it didn't update/change/check the encoding of the XmlDocument itself. If there is a mismatch, then the encoding of the xml won't match the encoding specified in the response.
Ian Boyd
A: 

Below is an example of the correct way I think. At least it is what I use. You need to do Response.Clear to get rid of any headers that are already populated. You need to pass the correct ContentType of text/xml. That is the way you serve xml. In general you want to serve it as charset UTF-8 as that is what most parsers are expecting. But I don't think it has to be that. But if you change it make sure to change your xml document declaration and indicate the charset in there. You need to use the XmlWriter so you can actually write in UTF-8 and not whatever charset is the default. And to have it properly encode your xml data in UTF-8.

   ' -----------------------------------------------------------------------------
   ' OutputDataSetAsXML
   '
   ' Description: outputs the given dataset as xml to the response object
   '
   ' Arguments:
   '    dsSource           - source data set
   '
   ' Dependencies:
   '
   ' History
   ' 2006-05-02 - WSR : created
   '
   Private Sub OutputDataSetAsXML(ByRef dsSource As System.Data.DataSet)

      Dim xmlDoc As System.Xml.XmlDataDocument
      Dim xmlDec As System.Xml.XmlDeclaration
      Dim xmlWriter As System.Xml.XmlWriter

      ' setup response
      Me.Response.Clear()
      Me.Response.ContentType = "text/xml"
      Me.Response.Charset = "utf-8"
      xmlWriter = New System.Xml.XmlTextWriter(Me.Response.OutputStream, System.Text.Encoding.UTF8)

      ' create xml data document with xml declaration
      xmlDoc = New System.Xml.XmlDataDocument(dsSource)
      xmlDoc.DataSet.EnforceConstraints = False
      xmlDec = xmlDoc.CreateXmlDeclaration("1.0", "UTF-8", Nothing)
      xmlDoc.PrependChild(xmlDec)

      ' write xml document to response
      xmlDoc.WriteTo(xmlWriter)
      xmlWriter.Flush()
      xmlWriter.Close()
      Response.End()

   End Sub
   ' -----------------------------------------------------------------------------
Will Rickards
A: 

Seems like at least 10 questions rolled into one here, a couple points.

Response.Clear - it really depends on what else is going on in the app - if you have httpmodules early in the pipeline that might be writing stuff you don't want - then clear it. Test it and find out. Fiddler or Wireshark useful for this.

Content Type to text/xml - yup - good idea - read up on HTTP spec as to why this is important. IMO anyone doing web work should have read the 1.0 and 1.1 spec at least once.

Encoding - how is your xml encoded - if it is utf-8, then say so, if not, say something else appropriate, just make sure they all match.

Page - personally, would use ashx or httpmodule, if you are using page, and want it a bit faster, get rid of autoeventwireup and bind the event handlers manually.

Would probably be a bit of a waste of memory to dump the xml into a string first, but it depends a lot on the size of the xml as to whether you would ever notice.

As others have suggested, saving the xml to the output stream probably the fastest, I would normally do that, but if you aren't sure, test it, don't rely on what you read on the interweb. Don't just believe anything I say.

For another approach, if the xml doesn't change that much, you could just write it to the disk and serve the file directly, which would likely be quite performant, but like everything in programming, it depends...

seanb
A: 

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
Ian Boyd