如何在ASP.NET中返回XML?
我遇到过许多在ASP.NET中返回XML的任务的一半解决scheme。 不过,我不想盲目地复制和粘贴大部分时间工作的代码, 我想要正确的代码,我想知道为什么它是正确的。 我要批评; 我需要信息; 我需要知识; 我想要了解。
下面是代码段,按照越来越复杂的顺序,代表我已经看到的一些部分解决scheme,包括每个引起的一些进一步的问题,以及我想在这里回答的问题。
一个彻底的答案必须解释为什么我们必须拥有或不能拥有以下任何东西,否则解释为什么它是不相关的。
- Response.Clear();
- Response.ContentType =“text / xml”;
- Response.ContentEncoding = Encoding.UTF8;
- Response.ContentEncoding = Encoding.UTF16;
- Response.ContentType =“text / xml; charset = utf-8”;
- Response.ContentType =“text / xml; charset = utf-16”;
- 到Response.End()
- 用正面文件内脏的aspx来撕掉
- 使用ashx文件
最后,想象一下你需要编写一个像这样的帮助函数的内容:
///<summary>Use this call inside your (Page_Xxx) method to write the ///xml to the web client. </summary> ///<remarks>See for https://stackoverflow.com/questions/543319/how-to-return-xml-in-asp-net ///for proper usage.</remarks> public static void ReturnXmlDocumentToWebClient( XmlDocument document, Page page) { ... }
我看到的每个解决scheme都是从一个空的aspx页面开始的,并从前面的文件中修剪掉所有的HTML(这会在Visual Studio中导致警告):
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="GetTheXml.aspx.cs" Inherits="GetTheXml" %>
接下来我们使用Page_Load
事件写入输出:
protected void Page_Load(object sender, EventArgs e) { String xml = "<foo>Hello, world!</foo>"; Response.Write(xml); }
我们是否需要将ContentType更改为“text / xml” ? 即:
protected void Page_Load(object sender, EventArgs e) { String xml = "<foo>Hello, world!</foo>"; Response.ContentType = "text/xml"; Response.Write(xml); }
我们是否需要先调用Response.Clear
?
protected void Page_Load(object sender, EventArgs e) { String xml = "<foo>Hello, world!</foo>"; Response.Clear(); Response.ContentType = "text/xml"; Response.Write(xml); }
我们真的需要打电话吗? 不要Response.Clear
做前面的步骤,确保前面的文件中的代码是空的(甚至没有空格或回车)在<% ... %>
之外是不必要的?
Response.Clear
是否使它更加健壮,以防有人在代码前面的文件中留下空行或空格?
使用ashx与空白的aspx主文件相同,因为据了解,它不会输出HTML?
我们是否需要调用Response.End
? 即:
protected void Page_Load(object sender, EventArgs e) { String xml = "<foo>Hello, world!</foo>"; Response.Clear(); Response.ContentType = "text/xml"; Response.Write(xml); Response.End(); }
Response.Write
之后还有什么可能发生,需要我们现在结束响应?
text/xml
的内容types是否足够,或者应该是text / xml; charset = utf-8 ?
protected void Page_Load(object sender, EventArgs e) { String xml = "<foo>Hello, world!</foo>"; Response.Clear(); Response.ContentType = "text/xml; charset=utf-8"; Response.Write(xml); Response.End(); }
还是应该专门不是那个? 在内容types中是否有字符集,但没有设置属性,搞砸了服务器?
为什么不是其他一些内容types,例如:
- UTF-8
- UTF-16
- UTF-16
应该在Response.ContentEncoding
指定字符集吗?
protected void Page_Load(object sender, EventArgs e) { String xml = "<foo>Hello, world!</foo>"; Response.Clear(); Response.ContentType = "text/xml"; Response.ContentEncoding = Encoding.UTF8; Response.Write(xml); Response.End(); }
使用Response.ContentEncoding
比干扰到Response.ContentType
更好吗? 情况更糟吗? 前者是否支持? 后者是?
我其实不想写一个string; 我想写出一个XmlDocument
。 有人build议我可以使用XmlWriter
:
protected void Page_Load(object sender, EventArgs e) { XmlDocument xml = GetXmlDocumentToShowTheUser(); Response.Clear(); Response.ContentType = "text/xml"; Response.ContentEncoding = Encoding.UTF8; using (TextWriter textWriter = new StreamWriter( Response.OutputStream, Encoding.UTF8)) { XmlTextWriter xmlWriter = new XmlTextWriter(textWriter); // Write XML using xmlWriter //TODO: How to do this? } }
请注意使用Response.OutputStream
,而不是Response.Write
。 这个好吗? 坏? 更好? 更差? 更快? 比较慢? 更多的内存密集? 内存密集度较低?
我读到你应该渲染
该页面的Render()方法中的XML,以避免使用Page_Load()时遇到的分块问题。
什么是组块 ? 什么是分块的问题,以及如何使用Page_Render
消除它们?
我不想写我的XmlDocument
对象的内容到一个string,然后写,因为这会浪费内存。 也就是说,其中任何一个都不好:
Response.Write(doc.ToString()); Response.Write(doc.InnerXml); xmlWrite.WriteString(doc.ToString()); xmlWrite.WriteString(doc.InnerXml);
类似的问题
如何在ASP.NET中返回XML
参考
如何在ASP.NET 1.1中从ASPX返回XML
将XML输出写入ASP.NET网页
你如何从ASP.NET输出XML?
在ASP.NET中创build一个ASHX处理程序
我find了正确的方法来将XML返回给ASP.NET中的客户端。 我认为,如果我指出了错误的方式,它会使正确的方式更容易理解。
不正确:
Response.Write(doc.ToString());
不正确:
Response.Write(doc.InnerXml);
不正确:
Response.ContentType = "text/xml"; Response.ContentEncoding = System.Text.Encoding.UTF8; doc.Save(Response.OutputStream);
正确:
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)
使用TextWriter
不要使用Response.OutputStream
请使用Response.Output
两者都是stream,但Output
是一个TextWriter 。 当一个XmlDocument
自己保存到一个TextWriter ,它将使用该TextWriter指定的编码 。 XmlDocument将自动更改xml声明节点以匹配TextWriter使用的编码。 例如在这种情况下,XML声明节点:
<?xml version="1.0" encoding="ISO-8859-1"?>
会成为
<?xml version="1.0" encoding="UTF-8"?>
这是因为TextWriter已被设置为UTF-8。 (更多关于这一点)。 由于TextWriter提供了字符数据,所以它将使用适合于其设置编码的字节序列进行编码。
不正确 :
doc.Save(Response.OutputStream);
在这个例子中,文档被错误地保存到OutputStream中,OutputStream不执行编码更改,可能与响应的内容编码或XML声明节点的指定编码不匹配。
正确
doc.Save(Response.Output);
XML文档被正确保存到TextWriter对象,确保编码得到正确处理。
设置编码
在头部给客户端的编码:
Response.ContentEncoding = ...
必须匹配XML文档的编码:
<?xml version="1.0" encoding="..."?>
必须与发送给客户端的字节序列中存在的实际编码相匹配。 要使所有这三件事情都一致,请设置单行:
Response.ContentEncoding = System.Text.Encoding.UTF8;
在Response对象上设置编码时,它将在TextWriter上设置相同的编码。 TextWriter的编码集导致XmlDocument更改xml声明 :
<?xml version="1.0" encoding="UTF-8"?>
当文件被保存时:
doc.Save(someTextWriter);
保存到响应输出
您不想将文档保存到二进制stream,或者写一个string:
不正确:
doc.Save(Response.OutputStream);
这里XML被错误地保存到二进制stream。 最终的字节编码顺序将不匹配XML声明或Web服务器响应的内容编码。
不正确:
Response.Write(doc.ToString()); Response.Write(doc.InnerXml);
这里的XML被错误地转换为一个没有编码的string。 XML声明节点未更新以反映响应的编码,并且响应未正确编码以匹配响应的编码。 另外,将XML存储在中间string中会浪费内存。
您不希望将XML保存为string,或者将XML填充到string和response.Write
写入一个string,因为:
- doesn't follow the encoding specified - doesn't set the XML declaration node to match - wastes memory
请使用doc.Save(Response.Output);
不要使用doc.Save(Response.OutputStream);
不要使用Response.Write(doc.ToString());
不要使用'Response.Write(doc.InnerXml);`
设置内容types
Response的ContentType必须设置为"text/xml"
。 如果没有,客户端将不知道你正在发送XML。
最终答案
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
完整的例子
罗布·肯尼迪有一个好处,我没有包括从头到尾的例子。
GetPatronInformation.ashx :
<%@ WebHandler Language="C#" Class="Handler" %> using System; using System.Web; using System.Xml; using System.IO; using System.Data.Common; //Why a "Handler" and not a full ASP.NET form? //Because many people online critisized my original solution //that involved the aspx (and cutting out all the HTML in the front file), //noting the overhead of a full viewstate build-up/tear-down and processing, //when it's not a web-form at all. (It's a pure processing.) public class Handler : IHttpHandler { public void ProcessRequest(HttpContext context) { //GetXmlToShow will look for parameters from the context XmlDocument doc = GetXmlToShow(context); //Don't forget to set a valid xml type. //If you leave the default "text/html", the browser will refuse to display it correctly context.Response.ContentType = "text/xml"; //We'd like UTF-8. context.Response.ContentEncoding = System.Text.Encoding.UTF8; //context.Response.ContentEncoding = System.Text.Encoding.UnicodeEncoding; //But no reason you couldn't use UTF-16: //context.Response.ContentEncoding = System.Text.Encoding.UTF32; //Or UTF-32 //context.Response.ContentEncoding = new System.Text.Encoding(500); //Or EBCDIC (500 is the code page for IBM EBCDIC International) //context.Response.ContentEncoding = System.Text.Encoding.ASCII; //Or ASCII //context.Response.ContentEncoding = new System.Text.Encoding(28591); //Or ISO8859-1 //context.Response.ContentEncoding = new System.Text.Encoding(1252); //Or Windows-1252 (a version of ISO8859-1, but with 18 useful characters where they were empty spaces) //Tell the client don't cache it (it's too volatile) //Commenting out NoCache allows the browser to cache the results (so they can view the XML source) //But leaves the possiblity that the browser might not request a fresh copy //context.Response.Cache.SetCacheability(HttpCacheability.NoCache); //And now we tell the browser that it expires immediately, and the cached copy you have should be refreshed context.Response.Expires = -1; context.Response.Cache.SetAllowResponseInBrowserHistory(true); //"works around an Internet Explorer bug" doc.Save(context.Response.Output); //doc saves itself to the textwriter, using the encoding of the text-writer (which comes from response.contentEncoding) #region Notes /* * 1. Use Response.Output, and NOT 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 the TextWriter. The XmlDocument will automatically change any * XML declaration node, ie: * <?xml version="1.0" encoding="ISO-8859-1"?> * to match the encoding used by the Response.Output's encoding setting * 2. The Response.Output TextWriter's encoding settings comes from the * Response.ContentEncoding value. * 3. Use doc.Save, not Response.Write(doc.ToString()) or Response.Write(doc.InnerXml) * 3. You DON'T want to save the XML to a string, or stuff the XML into a string * and response.Write that, because that * - doesn't follow the encoding specified * - wastes memory * * To sum up: by Saving to a TextWriter: the XML Declaration node, the XML contents, * and the HTML Response content-encoding will all match. */ #endregion Notes } private XmlDocument GetXmlToShow(HttpContext context) { //Use context.Request to get the account number they want to return //GET /GetPatronInformation.ashx?accountNumber=619 //Or since this is sample code, pull XML out of your rear: XmlDocument doc = new XmlDocument(); doc.LoadXml("<Patron><Name>Rob Kennedy</Name></Patron>"); return doc; } public bool IsReusable { get { return false; } } }
理想情况下,您可以使用ashx发送XML,尽pipe我允许ASPX中的代码拦截正常执行。
Response.Clear()
我不使用这个,如果你不确定你在响应中已经抛弃了任何东西,那么去find它,并摆脱它。
Response.ContentType = "text/xml"
当然,如果没有这种内容types,普通的客户端将不会接受XML格式的内容。
Response.Charset = "UTF-8";
让响应类正确处理构build内容types头。 使用UTF-8,除非你有一个非常好的理由不要。
Response.Cache.SetCacheability(HttpCacheability.NoCache); Response.Cache.SetAllowResponseInBrowserHistory(true);
如果不发送caching头,某些浏览器(即IE)会caching响应,随后的请求不一定会到达服务器。 您还需要AllowResponseInBrowser,如果你想通过HTTPS工作(由于IE中的另一个错误)。
要发送XmlDocument的内容,只需使用:
dom.Save(Response.OutputStream);
dom.Save(Response.Output);
只要确保编码匹配,(使用UTF-8的另一个好理由)。
XmlDocument
对象将自动调整其embedded的encoding="..."
编码为Response
(例如UTF-8
)
Response.End()
如果你真的必须在ASPX中,但它有点激烈,在ASHX不这样做。
下面是我想到的正确方法的一个例子。 至less这是我使用的。 你需要做Response.Clear来摆脱已经填充的头文件。 您需要传递正确的ContentType的text / xml。 这是你服务xml的方式。 一般来说,您希望将其作为字符集UTF-8来使用,因为这是大多数parsing器所期望的。 但我不认为这是必要的。 但是,如果你改变它,一定要改变你的XML文档声明,并指出在那里的字符集。 你需要使用XmlWriter,所以你可以用UTF-8编写,而不是默认的字符集。 并以UTF-8正确编码你的xml数据。
' ----------------------------------------------------------------------------- ' 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 ' -----------------------------------------------------------------------------
好像至less有10个问题在这里汇总成一个点,
Response.Clear – 这实际上取决于应用程序中还在发生什么 – 如果你有早期的httpmodules可能正在写你不想要的东西 – 那就清除它。 testing一下,找出答案。 提琴手或Wireshark对此有用。
内容types为text / xml – yup – 好主意 – 阅读HTTP规范,了解为什么这很重要。 海事组织任何人做networking工作应该已经阅读了1.0和1.1规范至less一次。
编码 – 你的xml编码如何 – 如果是utf-8,那就这么说,如果不是的话,说一些其他适当的东西,只要确保它们全都匹配。
如果你正在使用页面,页面 – 个人将使用ashx或httpmodule,并且希望它快一点,摆脱autoeventwireup并手动绑定事件处理程序。
可能会有点浪费内存,首先将xml转换为string,但这取决于您是否注意到xml的大小。
正如其他人所build议的,将xml保存到输出stream可能是最快的,我通常会这样做,但是如果您不确定,请testing它,不要依赖您在interweb上阅读的内容。 不要只相信我说的话。
换另一种方法,如果xml没有改变那么多,你可以把它写到磁盘上直接提供文件,这可能是相当高效的,但是像编程中的一切,这取决于…
我感到惊讶的是,似乎没有人提到可以使用.NET 4.0中提供的XDocument / XElement,并且使得输出XML更容易。
以下是将调用处理程序并接收stream数据并加载到xml文档中的服务器端代码
Stream stream = null; **Create a web request with the specified URL** WebRequest myWebRequest = WebRequest.Create(@"http://localhost/XMLProvider/XMLProcessorHandler.ashx"); **Senda a web request and wait for response.** WebResponse webResponse = myWebRequest.GetResponse(); **Get the stream object from response object** stream = webResponse.GetResponseStream(); XmlDocument xmlDoc = new XmlDocument(); **Load stream data into xml** xmlDoc.Load(stream);
下面是一个处理程序将返回在服务器端将包含xml数据的stream数据的方式。
这是将返回数据的处理程序代码。
public void ProcessRequest(HttpContext context) { StringBuilder xmlBuilder = new StringBuilder(); xmlBuilder.Append("<Names>"); xmlBuilder.Append("<Name>"); xmlBuilder.Append("Sheo"); xmlBuilder.Append("</Name>"); xmlBuilder.Append("</Names>"); context.Response.ContentType = "application/octet-stream"; context.Response.BinaryWrite(Encoding.UTF8.GetBytes(xmlBuilder.ToString())); context.Response.End(); }
你基本上已经回答了一切,所以我不确定这里的重点是什么?
FWIW 我会使用一个httphandler – 在调用一个页面生命周期方面似乎没有任何意义,并且必须处理裁剪视图状态和会话的各个部分,以及哪些对XML文档没有意义。 这就像买一辆车,剥下零件来制造你的摩托车。
内容types非常重要,请求者知道如何处理响应。