如何在ASP.NET中返回XML?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (121)

我遇到过许多在ASP.NET中返回XML的任务的一半解决方案。不过,我不想盲目地复制和粘贴大部分时间工作的代码,我想要正确的代码,我想知道为什么它是正确的。我要批评; 我需要信息; 我需要知识; 我想要理解。

下面是代码片段,按照日益复杂的顺序,代表了我所见过的部分解决方案,包括每个人所引发的一些进一步的问题,以及我希望在这里回答的问题。

一个彻底的答案必须解释为什么我们必须拥有或不能拥有以下任何东西,否则解释为什么它是不相关的。

  • 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)
{
   ...
}

我看到的每个解决方案都是从一个空的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足够,或者应该是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();
}

还是应该特别不是那样?在内容类型中是否有字符集,但没有设置属性,搞砸了服务器?

为什么不是其他一些内容类型,例如:

  • 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吗?它更糟吗?前者是否支持?后者是?

我其实不想写一个字符串; 我想写出一个XmlDocument

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对象的内容写入字符串,然后编写它,因为这会浪费内存。也就是说,其中任何一个都不好:

Response.Write(doc.ToString());
Response.Write(doc.InnerXml);
xmlWrite.WriteString(doc.ToString());
xmlWrite.WriteString(doc.InnerXml);

参考

在ASP.NET 1.1中如何从ASPX返回XML

将XML输出写入ASP.NET网页

你如何从ASP.NET输出XML?

在ASP.NET中创建一个ASHX处理程序

提问于
用户回答回答于

我找到了将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

两者都是流,但是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);

保存到响应输出

不希望将文档保存到二进制流,或者写一个字符串:

不正确:

doc.Save(Response.OutputStream);

这里XML被错误地保存到二进制流中。最终的字节编码序列将不匹配XML声明或Web服务器响应的内容编码。

不正确:

Response.Write(doc.ToString());
Response.Write(doc.InnerXml);

在这里,XML被错误地转换为一个没有编码的字符串。XML声明节点未更新以反映响应的编码,并且响应未正确编码以匹配响应的编码。另外,将XML存储在中间字符串中会浪费内存。

希望将XML保存为字符串,或者将XML填充到字符串和response.Write字符串中,因为:

- 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);`

设置内容类型

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&nbsp;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; } }
}
用户回答回答于

理想情况下,可以使用ashx发送XML,尽管我允许ASPX中的代码拦截正常执行。

Response.Clear()

我不使用这个,如果你不确定你已经在响应中抛弃了任何东西,那么去找它并摆脱它。

Response.ContentType = "text/xml"

当然,如果没有这种内容类型,普通客户端不会接受XML格式的内容。

 Response.Charset = "UTF-8";

让响应类正确处理构建内容类型头。使用UTF-8除非你有一个非常好的理由不要。

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

如果不发送缓存标头,某些浏览器(即IE)将缓存响应,随后的请求不一定会发送到服务器。如果希望通过HTTPS工作,您还需要AllowResponseInBrowser(由于IE中存在另一个错误)。

要发送XmlDocument的内容,只需使用:

dom.Save(Response.OutputStream);

dom.Save(Response.Output);

只要确保编码匹配,(使用UTF-8的另一个很好的理由)。

XmlDocument对象将自动调整其嵌入encoding="..."编码为Response(例如UTF-8

Response.End()

如果你真的必须在ASPX中,但它有点激烈,在ASHX不要这样做。

扫码关注云+社区