66 votes

Comment renvoyer XML en ASP.net?

J'ai rencontré beaucoup de demi-solutions pour le retour de XML dans ASP.Net. Je ne veux pas aveuglément copier-coller du code qui arrive à travailler la plupart du temps, cependant, je veux le droit de code, et je veux savoir pourquoi c'est bon. Je veux de la critique; j'ai besoin de renseignements, je veux savoir, je veux comprendre.

Ci-dessous sont des fragments de code, par ordre de complexité croissante, qui représente certains des solutions partielles que j'ai vu, y compris quelques-unes des autres questions que chacun causes, et sur laquelle j'aimerais avoir une réponse ici.

Approfondie de la réponse doit répondre à pourquoi nous devons avoir ou ne doit pas avoir les choses suivantes, ou expliquer pourquoi il n'est pas pertinent.

  • Réponse.Clear();
  • Réponse.ContentType = "text/xml";
  • Réponse.ContentEncoding = Encodage.UTF8;
  • Réponse.ContentEncoding = Encodage.UTF16;
  • Réponse.ContentType = "text/xml; charset=utf-8";
  • Réponse.ContentType = "text/xml; charset=utf-16";
  • Réponse.Fin()
  • À l'aide d'un aspx avec l'avant-fichier tripes arrachées
  • À l'aide d'un fichier ashx

En fin de compte, imaginez que vous avez besoin pour écrire le contenu d'une aide de la fonction comme ceci:

///<summary>Use this call inside your (Page_Xxx) method to write the 
///xml to the web client. </summary>
///<remarks>See for http://stackoverflow.com/questions/543319/how-to-return-xml-in-asp-net 
///for proper usage.</remarks>
public static void ReturnXmlDocumentToWebClient(
    XmlDocument document, 
    Page page)
{
   ...
}

Chaque solution que je vois commence avec la prise de vide d'une page aspx, et de tailler tout le HTML de l'avant du fichier (ce qui provoque des avertissements dans Visual Studio):

<%@ Page Language="C#" 
      AutoEventWireup="true" 
      CodeFile="GetTheXml.aspx.cs" 
      Inherits="GetTheXml" %>

Ensuite, nous utilisons l' Page_Load événement à écrire à la sortie:

protected void Page_Load(object sender, EventArgs e)
{
   String xml = "<foo>Hello, world!</foo>";

   Response.Write(xml);
}

Devons-nous modifier le 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);
}

Devons-nous appeler Response.Clear premier?

protected void Page_Load(object sender, EventArgs e)
{
   String xml = "<foo>Hello, world!</foo>";

   Response.Clear();
   Response.ContentType = "text/xml";
   Response.Write(xml);
}

Avons-nous vraiment besoin d'appeler qui? N'a pas d' Response.Clear faire l'étape préalable de s'assurer que le code dans le fichier était vide (même pas un espace ou un retour chariot) à l'extérieur de l' <% ... %> inutile?

N' Response.Clear la rendre plus solide, dans le cas où quelqu'un a laissé une ligne vide ou un espace dans le code du front de fichier?

Est l'aide de ashx la même chose qu'un vide aspx fichier principal, car il est entendu qu'il ne va pas à la sortie de l'HTML?


Devons-nous appeler 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();
}

Quoi d'autre pourrait éventuellement se produire après l' Response.Write qui a besoin de nous pour mettre fin à la réponse de la droite maintenant?


Est le content-type text/xml suffisant, ou faut-il plutôt 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();
}

Ou faut-il précisément de ne pas être qui? Le fait d'avoir un jeu de caractères dans le type de contenu, mais pas la définition de la propriété, revissez le serveur?

Pourquoi pas sur un autre type de contenu, par exemple:

  • UTF-8
  • utf-16
  • UTF-16

Si le charset être spécifié en 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();
}

Est l'aide de Response.ContentEncoding de mieux que de brouillage en Response.ContentType? Est-ce pire? C'est l'ancienne pris en charge? Est le dernier?


Je n'ai pas vraiment envie d'écrire une Chaîne de caractères; je veux écrire un XmlDocument. Quelqu'un suggère que je peux utiliser l' 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?
   }
}

Notez l'utilisation de l' Response.OutputStream, plutôt que d' Response.Write. Est-ce bien? Mauvaise? Mieux? Le pire? Plus vite? Plus lent? Plus de mémoire intensive? Moins gourmande en mémoire?


J'ai lu que vous devez rendre

le XML de la page de la méthode Render() pour éviter les problèmes de segmentation rencontrés lors de l'utilisation Page_Load().

Qu'est-ce que chunking? Quels sont les problèmes de segmentation, et comment utiliser l'aide d' Page_Render les éliminer?


Je ne veux pas écrire le contenu de mon XmlDocument objet en chaîne de caractères, puis d'écrire que parce que les déchets de la mémoire. C'est l'un de ces serait mauvais:

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

Des Questions Similaires

Comment renvoyer du XML dans ASP.NET

Références

Comment Renvoyer du XML à Partir ASPX dans ASP.NET 1.1

L'écriture xml de sortie à l'asp .net page web

Comment pensez-vous de la sortie XML à partir d'ASP.NET?

La création d'un ASHX gestionnaire dans ASP.NET

79voto

Ian Boyd Points 50743

j'ai trouvé la bonne façon de le renvoyer du XML à un client dans le ASP.NET. je pense que si je pointe du doigt les mauvaises manières, ça va faire de la bonne manière plus compréhensible.

Incorrect:

Response.Write(doc.ToString()); 

Incorrect:

Response.Write(doc.InnerXml); 

Incorrect:

Response.ContentType = "text/xml";
Response.ContentEncoding = System.Text.Encoding.UTF8;
doc.Save(Response.OutputStream); 

Correct:

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)

Utiliser un TextWriter

N' utilisez Response.Output

Ne pas utiliser Response.OutputStream

Les deux sont des cours d'eau, mais Output est un TextWriter. Lorsqu'un XmlDocument enregistre lui-même à un TextWriter, il utilise l' encodage spécifié par TextWriter. XmlDocument va automatiquement modifier le nœud déclaration xml pour correspondre à l'encodage utilisé par le TextWriter. par exemple, dans ce cas, le nœud déclaration xml:

<?xml version="1.0" encoding="ISO-8859-1"?>

allait devenir

<?xml version="1.0" encoding="UTF-8"?>

C'est parce que le TextWriter a été mis en UTF-8. (plus sur cela dans un instant). Comme le TextWriter est nourri de données de caractère, il va coder avec les séquences d'octets approprié pour son codage du jeu.

Incorrect:

doc.Save(Response.OutputStream);

Dans cet exemple, le document est enregistré de manière incorrecte à l'OutputStream, qui effectue l'encodage n'changer et peuvent ne pas correspondre à la réponse au contenu de l'encodage ou de la déclaration xml nœud spécifié pour l'encodage.

Correct

doc.Save(Response.Output);

Le document xml est correctement enregistré pour un objet TextWriter, assurant le codage est correctement géré.


Codage Du Jeu

L'encodage pour le client dans l'en-tête:

Response.ContentEncoding = ... 

doit correspondre au document xml d'encodage:

<?xml version="1.0" encoding="..."?>

doit correspondre à l'encodage réel présent dans les séquences d'octets envoyés au client. Pour faire ces trois choses, d'accord, définissez la seule ligne:

Response.ContentEncoding = System.Text.Encoding.UTF8;

Lorsque le codage est défini sur la Réponse de l'objet, il définit l'encodage sur le TextWriter. L'encodage de la TextWriter causes de la XmlDocument pour modifier la déclaration xml:

<?xml version="1.0" encoding="UTF-8"?>

lorsque le document est Enregistré:

doc.Save(someTextWriter);

Enregistrer à la Sortie de la réponse

Vous ne souhaitez pas enregistrer le document dans un flux binaire, ou d'écrire une chaîne de caractères:

Incorrect:

doc.Save(Response.OutputStream);

Ici, le xml est mal enregistré pour un flux binaire. Le dernier octet codant pour la séquence ne correspond pas à la déclaration xml, ou le serveur web de la réponse de l'encodage de contenu.

Incorrect:

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

Ici, le xml est mal converti en chaîne, qui n'a pas de codage. Le nœud déclaration xml n'est pas mis à jour pour refléter l'encodage de la réponse, et la réponse n'est pas codé correctement pour correspondre à la réponse de l'encodage. Par ailleurs, la conservation du xml dans une position intermédiaire de la chaîne de déchets de la mémoire.

Vous n'avez pas souhaitez Enregistrer le fichier xml en une chaîne de caractères, ou des trucs du xml dans une chaîne de caractères et la réponse.Écrire une chaîne de caractères, parce que:

- doesn't follow the encoding specified
- doesn't set the xml declaration node to match
- wastes memory

N' utilisez doc.Save(Response.Output);

Ne pas utiliser doc.Save(Response.OutputStream);

Ne pas utiliser Response.Write(doc.ToString());

Ne pas utiliser de Réponse.Écrire(doc.InnerXml);`


Définir le type de contenu

La Réponse de la ContentType doit être réglé sur " "text/xml"'. Si pas, le client ne saura pas que vous l'envoyez xml.

Réponse Finale

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

Exemple Complet

Rob Kennedy a eu le bon point que je n'ai pas réussi à inclure la start-to-finish exemple.

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 ie bug"

      doc.Save(context.Response.Output); //doc save 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 ass:
      XmlDocument doc = new XmlDocument();
      doc.LoadXml("<Patron><Name>Rob Kennedy</Name></Patron>")

      return doc;
   }

   public bool IsReusable { get { return false; } }
}

16voto

AnthonyWJones Points 122520

L'idéal serait d'utiliser un ashx pour envoyer du XML bien que je permets de code dans un ASPX pour intercepter l'exécution normale.

Response.Clear()

Je ne pas l'utiliser si vous n'êtes pas sûr que vous avez sous-évaluées rien dans la réponse déjà l'aller trouver et se débarrasser de lui.

Response.ContentType = "text/xml"

Certainement, un client commun de ne pas accepter le contenu au format XML sans ce type de contenu présent.

 Response.Charset = "UTF-8";

Laissez la réponse de la classe de gérer la construction du type de contenu de l'en-tête correctement. Utiliser l'UTF-8, sauf si vous avez vraiment, vraiment une bonne raison de ne pas.

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

Si vous n'avez pas d'envoyer des en-têtes de cache certains navigateurs (notamment IE) met en cache la réponse, les demandes ultérieures ne viendra pas nécessairement pour le serveur. Vous devez également AllowResponseInBrowser si vous voulez que cela fonctionne sur HTTPS (en raison de encore un autre bug dans IE).

Pour envoyer le contenu d'un XmlDocument suffit d'utiliser:

dom.Save(Response.OutputStream);

dom.Save(Response.Output);

Juste être sûr que les codages de match, (une autre bonne raison d'utiliser l'UTF-8).

L' XmlDocument objet sera automatiquement ajuster embarqué encoding="..." de l'encodage de l' Response (par exemple, UTF-8)

Response.End()

Si vous avez vraiment dans une ASPX, mais c'est un peu drastique, dans un ASHX ne pas le faire.

0voto

Will Rickards Points 1929

Ci-dessous est un exemple de la façon correcte je pense. Au moins, c'est ce que j'utilise. Ce que vous devez faire Réponse.Claire de se débarrasser de toutes les en-têtes qui sont déjà renseignés. Vous devez passer le bon ContentType de texte/xml. C'est la façon dont vous servir xml. En général, vous voulez la servir comme jeu de caractères UTF-8 qu'est ce que la plupart des analyseurs sont attendus. Mais je ne pense pas que ce soit comme cela. Mais si vous le modifier assurez-vous de modifier votre document xml de déclaration et d'indiquer le jeu de caractères. Vous devez utiliser le XmlWriter de sorte que vous pouvez réellement écrire en UTF-8 et pas n'importe lequel jeu de caractères par défaut. Et de l'avoir correctement l'encodage de vos données xml en 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
   ' -----------------------------------------------------------------------------

0voto

seanb Points 5267

Semble au moins 10 questions roulé dans un ici, un couple de points.

Réponse.Claire - cela dépend vraiment de ce qui se passe dans la app - si vous avez httpmodules tôt dans le pipeline qui pourrait être d'écrire des choses que vous ne voulez pas - puis l'effacer. Tester et découvrir. Fiddler ou Wireshark utile pour cela.

Type de contenu text/xml - oui, bonne idée de lire sur HTTP spec: pourquoi c'est important. OMI tous ceux qui font web de travail devrait avoir lu la 1.0 et 1.1 spec au moins une fois.

Encodage - comment est votre codée au format xml - si c'est de l'utf-8, alors dites-le, si non, dire quelque chose d'autre échéant, assurez-vous qu'ils correspondent à tous.

Page - personnellement, serait d'utiliser ashx ou httpmodule, si vous utilisez la page, et que vous voulez un peu plus vite, se débarrasser de autoeventwireup et lier les gestionnaires d'événements manuellement.

Serait probablement un peu du gaspillage de mémoire pour vider les données xml dans une chaîne, mais cela dépend beaucoup de la taille de l'xml de savoir si vous jamais remarqué.

Comme d'autres l'ont suggéré, l'économie de l'xml pour le flux de sortie probablement le plus rapide, je le ferais normalement, mais si vous n'êtes pas sûr, de le tester, ne comptez pas sur ce que vous lisez sur l'interweb. Ne vous contentez pas de croire ce que je dis.

Pour une autre approche, si le document xml n'a pas beaucoup changé, vous pouvez simplement écrire sur le disque et de servir directement le fichier, ce qui serait susceptible d'être assez performant, mais comme tout dans la programmation, ça dépend...

0voto

Peter Bromberg Points 1066

Je suis surpris que personne ne semble avoir jamais mentionné que vous pouvez utiliser XDocument / XElement, disponibles dans .NET 4.0, ce qui facilite beaucoup la sortie de XML.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X