我在ASP.NET中返回XML的任务遇到了很多半解决方案.我不想盲目地复制和粘贴一些恰好在大多数情况下工作的代码; 我想要正确的代码,我想知道它为什么是正确的.我要批评; 我想要信息; 我需要知识; 我想要理解.
下面是代码片段,按照复杂性的增加顺序,代表我看到的一些部分解决方案,包括每个问题引起的一些问题,以及我想在这里回答的问题.
一个彻底的答案必须解决为什么我们必须拥有或不得拥有以下任何东西,或者解释为什么它无关紧要.
最后,想象一下你需要编写一个这样的辅助函数的内容:
///<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)
{
...
}
Run Code Online (Sandbox Code Playgroud)
我看到的每个解决方案都从一个空的aspx页面开始,并从前端文件中删除所有HTML(这会在Visual Studio中导致警告):
<%@ Page Language="C#"
AutoEventWireup="true"
CodeFile="GetTheXml.aspx.cs"
Inherits="GetTheXml" %>
Run Code Online (Sandbox Code Playgroud)
接下来我们使用Page_Load事件写入输出:
protected void Page_Load(object sender, EventArgs e)
{
String xml = "<foo>Hello, world!</foo>";
Response.Write(xml);
}
Run Code Online (Sandbox Code Playgroud)
我们需要将ContentType更改为"text/xml"吗?即:
protected void Page_Load(object sender, EventArgs e)
{
String xml = "<foo>Hello, world!</foo>";
Response.ContentType = "text/xml";
Response.Write(xml);
}
Run Code Online (Sandbox Code Playgroud)
我们需要先打电话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);
}
Run Code Online (Sandbox Code Playgroud)
我们真的需要打电话吗?是不是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();
}
Run Code Online (Sandbox Code Playgroud)
还有什么可能发生以后Response.Write,需要我们结束的响应,现在?
内容类型是否text/xml足够,或者应该是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();
}
Run Code Online (Sandbox Code Playgroud)
或者它应该特别不是那样的?在内容类型中有一个字符集,但没有设置属性,搞砸了服务器?
为什么不是其他一些内容类型,例如:
是否应该指定字符集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();
}
Run Code Online (Sandbox Code Playgroud)
使用Response.ContentEncoding比干扰更好Response.ContentType吗?更糟糕吗?前者是否受到支持?是后者吗?
我实际上并不想写出一个字符串; 我想写出来XmlDocument.有人建议我可以使用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?
}
}
Run Code Online (Sandbox Code Playgroud)
注意使用Response.OutputStream,而不是Response.Write.这个好吗?坏?更好?更差?快点?慢点?更多内存密集型?内存密集度较低?
我读过你应该渲染
页面的Render()方法中的XML,以避免使用Page_Load()时遇到的分块问题.
什么是分块?分块有什么问题,如何使用Page_Render消除它们?
我不想将我的XmlDocument对象的内容写入字符串然后写,因为这会浪费内存.也就是说,其中任何一个都是坏的:
Response.Write(doc.ToString());
Response.Write(doc.InnerXml);
xmlWrite.WriteString(doc.ToString());
xmlWrite.WriteString(doc.InnerXml);
Run Code Online (Sandbox Code Playgroud)
类似的问题
参考
Ian*_*oyd 67
我找到了在ASP.NET中将XML返回给客户端的正确方法.我想如果我指出错误的方法,它将使正确的方式更容易理解.
不正确:
Response.Write(doc.ToString());
Run Code Online (Sandbox Code Playgroud)
不正确:
Response.Write(doc.InnerXml);
Run Code Online (Sandbox Code Playgroud)
不正确:
Response.ContentType = "text/xml";
Response.ContentEncoding = System.Text.Encoding.UTF8;
doc.Save(Response.OutputStream);
Run Code Online (Sandbox Code Playgroud)
正确:
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)
Run Code Online (Sandbox Code Playgroud)
千万不能使用Response.OutputStream
不要使用Response.Output
两者都是流,但是Output是TextWriter.当XmlDocument将自身保存到TextWriter时,它将使用该TextWriter指定的编码.XmlDocument将自动更改xml声明节点以匹配TextWriter使用的编码.例如,在这种情况下,XML声明节点:
<?xml version="1.0" encoding="ISO-8859-1"?>
Run Code Online (Sandbox Code Playgroud)
会成为
<?xml version="1.0" encoding="UTF-8"?>
Run Code Online (Sandbox Code Playgroud)
这是因为TextWriter已设置为UTF-8.(稍等一下).当TextWriter被输入字符数据时,它将使用适合其设置编码的字节序列对其进行编码.
不正确:
doc.Save(Response.OutputStream);
Run Code Online (Sandbox Code Playgroud)
在此示例中,文档被错误地保存到OutputStream,后者不执行编码更改,并且可能与响应的内容编码或XML声明节点的指定编码不匹配.
正确
doc.Save(Response.Output);
Run Code Online (Sandbox Code Playgroud)
XML文档正确保存到TextWriter对象,确保正确处理编码.
标头中给客户端的编码:
Response.ContentEncoding = ...
Run Code Online (Sandbox Code Playgroud)
必须匹配XML文档的编码:
<?xml version="1.0" encoding="..."?>
Run Code Online (Sandbox Code Playgroud)
必须匹配发送到客户端的字节序列中存在的实际编码.为了使所有这三件事达成一致,设置单行:
Response.ContentEncoding = System.Text.Encoding.UTF8;
Run Code Online (Sandbox Code Playgroud)
在Response对象上设置编码时,它会在TextWriter上设置相同的编码.TextWriter的编码集导致XmlDocument更改xml声明:
<?xml version="1.0" encoding="UTF-8"?>
Run Code Online (Sandbox Code Playgroud)
文档保存时:
doc.Save(someTextWriter);
Run Code Online (Sandbox Code Playgroud)
您不希望将文档保存为二进制流,也不想写入字符串:
不正确:
doc.Save(Response.OutputStream);
Run Code Online (Sandbox Code Playgroud)
这里XML被错误地保存到二进制流中.最终字节编码序列与XML声明或Web服务器响应的内容编码不匹配.
不正确:
Response.Write(doc.ToString());
Response.Write(doc.InnerXml);
Run Code Online (Sandbox Code Playgroud)
这里XML被错误地转换为字符串,该字符串没有编码.XML声明节点未更新以反映响应的编码,并且未正确编码响应以匹配响应的编码.此外,将XML存储在中间字符串中会浪费内存.
您不希望将XML保存到字符串中,或者将XML填充到字符串和response.Write字符串中,因为:
- doesn't follow the encoding specified
- doesn't set the XML declaration node to match
- wastes memory
Run Code Online (Sandbox Code Playgroud)
不要使用doc.Save(Response.Output);
千万不能使用doc.Save(Response.OutputStream);
千万不能使用Response.Write(doc.ToString());
千万不能使用"的Response.Write(doc.InnerXml);`
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
Run Code Online (Sandbox Code Playgroud)
Rob Kennedy有一个很好的观点,即我没有包括从头到尾的例子.
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, i.e.:
* <?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; } }
}
Run Code Online (Sandbox Code Playgroud)
Ant*_*nes 15
理想情况下,您会使用ashx发送XML,尽管我允许ASPX中的代码拦截正常执行.
Response.Clear()
Run Code Online (Sandbox Code Playgroud)
我不使用这个,如果你不确定你已经在响应中丢弃任何东西,那么就去找它并摆脱它.
Response.ContentType = "text/xml"
Run Code Online (Sandbox Code Playgroud)
当然,如果不存在此内容类型,公共客户端将不会将内容接受为XML.
Response.Charset = "UTF-8";
Run Code Online (Sandbox Code Playgroud)
让响应类处理正确构建内容类型标头.使用UTF-8,除非你有一个非常,非常好的理由不这样做.
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetAllowResponseInBrowserHistory(true);
Run Code Online (Sandbox Code Playgroud)
如果您不发送缓存标头,某些浏览器(即IE)将缓存响应,后续请求不一定会到达服务器.如果您希望它通过HTTPS工作,您还需要AllowResponseInBrowser(由于IE中的另一个错误).
要发送XmlDocument的内容,只需使用:
dom.Save(Response.OutputStream);
Run Code Online (Sandbox Code Playgroud)
dom.Save(Response.Output);
Run Code Online (Sandbox Code Playgroud)
只要确保编码匹配,(使用UTF-8的另一个好理由).
该XmlDocument对象将自动将其嵌入encoding="..."编码调整为Response(例如UTF-8)
Response.End()
Run Code Online (Sandbox Code Playgroud)
如果你真的需要在ASPX中,但它有点激烈,在ASHX中不要这样做.