Как вернуть XML в ASP.NET? - PullRequest
       43

Как вернуть XML в ASP.NET?

56 голосов
/ 13 февраля 2009

Я столкнулся со многими половинными решениями задачи возврата XML в ASP.NET. Однако я не хочу слепо копировать и вставлять код, который работает в большинстве случаев; Я хочу правильный код и хочу знать , почему это правильно. Я хочу критики; Я хочу информацию; Я хочу знания; Я хочу понимания.

Ниже приведены фрагменты кода в порядке возрастания сложности, представляющие некоторые частичные решения, которые я видел, включая некоторые дополнительные вопросы, которые вызывает каждый из них, и на которые я бы хотел ответить здесь.

В подробном ответе должен быть рассмотрен вопрос о том, почему должен иметь или не должен иметь какие-либо из следующих вещей, или же объяснить, почему это не имеет значения.

  • 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" ? I.e.:

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 его более надежным в случае, если кто-то оставил пустую строку или пробел в файле front-code?

Использует ли ashx то же самое, что и пустой основной файл aspx, потому что понятно, что он не будет выводить HTML?


Нужно ли нам звонить Response.End? I.e.:

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; кодировка = 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();
}

Или конкретно не ? Имеет ли кодировка в типе контента, но не устанавливает свойство, испортить сервер?

Почему бы не какой-нибудь другой тип контента, например ::1010 *

  • 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. Кто-то предлагает мне использовать 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. Это хорошо? Плохой? Лучше? Хуже? Быстрее? Помедленнее? Больше памяти? Меньше памяти?


Я прочитал что вы должны сделать

XML в методе Render () страницы чтобы избежать проблем с кусками встречается при использовании Page_Load ().

Что такое chunking ? Какие проблемы с чанкингом и как их использование с помощью Page_Render устраняет их?


Я не хочу записывать содержимое моего XmlDocument объекта в строку, а затем записывать это, потому что это тратит впустую память. То есть любой из них будет плох:

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

Похожие вопросы

Как вернуть XML в ASP.NET

Ссылки

Как вернуть XML из ASPX в ASP.NET 1.1

Запись вывода XML на веб-страницу ASP.NET

Как вы выводите XML из ASP.NET?

Создание обработчика ASHX в ASP.NET

Ответы [ 9 ]

64 голосов
/ 29 января 2010

Я нашел правильный способ вернуть 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

Do not use Response.OutputStream

Do Использование 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, который не выполняет изменения кодировки и может не соответствовать кодировке содержимого ответа или указанной кодировке узла объявления 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 или кодировке содержимого ответа веб-сервера.

Неправильно:

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

Do use doc.Save(Response.Output);

Do not use doc.Save(Response.OutputStream);

Do not use Response.Write(doc.ToString());

Не не использовать 'Response.Write (doc.InnerXml); `


Установить тип контента

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; } }
}
15 голосов
/ 13 февраля 2009

В идеале вы должны использовать 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) будут кэшировать ответ, последующие запросы не обязательно будут поступать на сервер. Вам также необходимо AllowResponseInBrowser, если вы хотите, чтобы это работало по HTTPS (из-за еще одной ошибки в IE).

Для отправки содержимого XmlDocument просто используйте:

dom.Save(Response.OutputStream);

dom.Save(Response.Output);

Просто убедитесь, что кодировки совпадают (еще одна веская причина для использования UTF-8).

Объект XmlDocument автоматически настроит встроенную кодировку encoding="..." на кодировку Response (например, UTF-8)

Response.End()

Если вам действительно нужно в ASPX, но это немного радикально, в ASHX не делайте этого.

0 голосов
/ 25 января 2019
XmlDocument xd = new XmlDocument();
xd.LoadXml(xmlContent);

context.Response.Clear();
context.Response.ContentType = "text/xml";
context.Response.ContentEncoding = System.Text.Encoding.UTF8;
xd.Save(context.Response.Output);
context.Response.Flush();
context.Response.SuppressContent = true;
context.ApplicationInstance.CompleteRequest();
0 голосов
/ 18 августа 2016

Ниже приведен код на стороне сервера, который вызывает обработчик и получает данные потока и загружает их в 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);
0 голосов
/ 18 августа 2016

Ниже приведен способ, которым обработчик возвращает потоковые данные, которые будут содержать данные XML на стороне сервера.

Вот код обработчика, который возвращает данные.

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

    }
0 голосов
/ 21 июня 2011

Я удивлен, что никто, кажется, никогда не упоминал о том, что вы можете использовать XDocument / XElement, который доступен в .NET 4.0 и упрощающий вывод XML.

0 голосов
/ 13 февраля 2009

Похоже, по крайней мере 10 вопросов в одном здесь, пару баллов.

Response.Clear - это действительно зависит от того, что еще происходит в приложении - если в начале конвейера у вас есть http-модули, которые могут писать вещи, которые вам не нужны, - тогда очистите их. Проверьте это и узнайте. Для этого полезны скрипач или Wireshark.

Тип содержимого в текст / xml - yup - хорошая идея - прочитайте спецификацию HTTP о том, почему это важно. IMO любой, кто занимается веб-работой, должен был прочитать спецификации 1.0 и 1.1 хотя бы один раз.

Кодировка - как кодируется ваш xml - если это utf-8, то скажите так, если нет, скажите что-нибудь еще подходящее, просто убедитесь, что они все совпадают.

Страница - лично, будет использовать ashx или httpmodule, если вы используете страницу и хотите ее немного быстрее, избавиться от autoeventwireup и связать обработчики событий вручную.

Вероятно, было бы немного потрачено впустую памяти, чтобы сначала скопировать xml в строку, но это во многом зависит от размера xml в отношении того, заметите ли вы когда-нибудь.

Как и другие предлагали, сохранение xml в выходной поток, вероятно, было бы самым быстрым, я обычно делал бы это, но, если вы не уверены, протестируйте его, не полагайтесь на то, что вы читаете в Интернете. Не верь всему, что я говорю.

Для другого подхода, если xml не так сильно меняется, вы можете просто записать его на диск и напрямую передать файл, что, вероятно, будет весьма производительным, но, как и все в программировании, зависит ...

0 голосов
/ 13 февраля 2009

Ниже приведен пример правильного способа, которым я считаю. По крайней мере, это то, что я использую. Вам нужно сделать Response.Clear, чтобы избавиться от любых заголовков, которые уже заполнены. Вам нужно передать правильный ContentType text / xml. Вот как вы служите XML. В общем, вы хотите использовать его как кодировку UTF-8, поскольку именно этого ожидает большинство анализаторов. Но я не думаю, что это должно быть так. Но если вы измените его, обязательно измените объявление документа XML и укажите там кодировку. Вам нужно использовать XmlWriter, чтобы вы могли писать на UTF-8, а не на той кодировке, которая используется по умолчанию. И чтобы он правильно кодировал ваши XML-данные в 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
   ' -----------------------------------------------------------------------------
0 голосов
/ 13 февраля 2009

Вы в основном уже ответили на все и все, так что я не уверен, какой смысл здесь?

FWIW Я использовал бы httphandler - кажется, что нет смысла вызывать жизненный цикл страницы и иметь дело с обрывом битов представления состояния и сеанса, а также того, что вы не имеете смысла XML док. Это все равно что покупать автомобиль и разбирать его на запчасти, чтобы сделать свой мотоцикл.

И тип контента - все это важно, это то, как запрашивающий знает, что делать с ответом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...