草庐IT

c# - 如何在 ASP.NET 中返回 XML?

coder 2024-06-23 原文

对于在 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 . Someone suggests I can use the 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 .这个好吗?坏的?更好的?更差?快点?慢点?内存更密集?更少的内存占用?


read你应该渲染

the XML in the page’s Render() method to avoid problems with chunking encountered when using Page_Load().

什么是分块? 分块有什么问题,如何使用 Page_Render消灭他们?


我不想写我的 XmlDocument 的内容object 到一个字符串中,然后写入它,因为这会浪费内存。也就是说,任何这些都是不好的:

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

类似问题

How to return XML in ASP.NET

引用资料

How Return XML From ASPX in ASP.NET 1.1

Writing XML output to an ASP.NET webpage

How do you output XML from ASP.NET?

Creating an ASHX handler in ASP.NET

最佳答案

我找到了在 ASP.NET 中将 XML 返回给客户端的正确方法。我认为如果我指出错误的方法,将使正确的方法更易于理解。

不正确:

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

两者都是流,但 OutputTextWriter .当 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,它不执行任何编码更改,并且可能与响应的内容编码或 XML 声明节点的指定编码不匹配。

正确

doc.Save(Response.Output);

XML 文档正确保存到 TextWriter 对象,确保正确处理编码。


设置编码

header 中给客户端的编码:

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 声明或网络服务器响应的内容编码不匹配。

不正确:

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

此处 XML 被错误地转换为没有编码的字符串。 XML 声明节点未更新以反射(reflect)响应的编码,并且响应未正确编码以匹配响应的编码。此外,将 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

完整示例

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&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; } }
}

关于c# - 如何在 ASP.NET 中返回 XML?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/543319/

有关c# - 如何在 ASP.NET 中返回 XML?的更多相关文章

  1. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  2. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  3. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  4. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  5. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  6. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  7. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  8. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  9. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  10. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

随机推荐