it-swarm.dev

Jak vrátit XML v ASP.NET?

Setkal jsem se s mnoha polo-řešení úkolu vracet XML v ASP.NET. Nechci však slepě kopírovat a vkládat nějaký kód, který se po většinu času stane, že funguje; Chci kód vpravo a chci vědět proč je to správné. Chci kritiku; Chci informace; Chci znalosti; Chci pochopení.

Níže jsou fragmenty kódu, v pořadí, v jakém se zvyšuje složitost, představující některá z dílčích řešení, která jsem viděl, včetně některých dalších otázek, z nichž každá z nich způsobuje, a které bych zde rád odpověděl.

Důkladná odpověď musí řešit, proč máme musí mít nebo nesmí mít některou z následujících věcí, nebo jinak vysvětlit, proč je to irelevantní.

  • Response.Clear ();
  • Response.ContentType = "text/xml";
  • Response.ContentEncoding = Kódování.UTF8;
  • Response.ContentEncoding = Kódování.UTF16;
  • Response.ContentType = "text/xml; charset = utf-8";
  • Response.ContentType = "text/xml; charset = utf-16";
  • Response.End ()
  • Použitím aspx s čárkami předních souborů vytrhl
  • Použití souboru ashx

Nakonec si představte, že je třeba napsat obsah funkce pomocníka takto:

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

Každé řešení, které vidím, začíná odebráním prázdné stránky aspx a oříznutím celého kódu HTML z předního souboru (což způsobuje varování v aplikaci Visual Studio):

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

Dále použijeme událost Page_Load k zápisu na výstup:

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

   Response.Write(xml);
}

Potřebujeme změnit ContentTypeto "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);
}

Musíme nejprve zavolat 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);
}

Opravdu to musíme nazvat? Neprovádí Response.Clear předchozí krok, aby se ujistil, že kód v předním souboru byl prázdný (ani mezera nebo návrat vozíku) mimo <% ... %> zbytečný?

Response.Clear, aby to bylo robustnější, v případě, že někdo nechal prázdný prázdný řádek nebo mezeru v souboru kódu?

Používá ashx stejně jako prázdný hlavní soubor aspx, protože se rozumí, že to nebude výstup HTML?


Potřebujeme zavolat Response.End? Tj.:

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

Co jiného by se mohlo stát po Response.Write, které potřebuje, abychom ukončili odpověď právě teď?


Je obsah typu text/xml dostačující, nebo by měl být místo toho 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();
}

Nebo by to mělo specificky nebýt, že? Má mít znakovou sadu v obsahu typu, ale ne nastavení vlastnosti, šroubování serveru?

Proč ne jiný typ obsahu, např .:

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

Má být znaková sada zadána v 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();
}

Používá Response.ContentEncoding lépe než rušení do Response.ContentType? Je to horší? Je první podporován? Je to druhé?


Já vlastně nechci psát String ven; Chci napsat XmlDocument. Někdo navrhuje použít 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?
   }
}

Všimněte si použití Response.OutputStream, spíše než Response.Write. Je tohle dobré? Špatný? Lepší? Horší? Rychlejší? Pomaleji? Intenzivnější paměť? Méně intenzivní paměť?


I read , které byste měli vykreslit

xML v metodě Render () stránky, aby se předešlo problémům s chunkingem při použití Page_Load ().

Co je to chunking? Jaké jsou problémy s chunking a jak je pomocí Page_Render eliminovat?


Nechci zapisovat obsah mého XmlDocument objektu do řetězce a pak to napsat, protože to plýtvá pamětí. To znamená, že každý z nich by byl špatný:

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

Podobné otázky

Jak vrátit XML v ASP.NET

Odkazy

Jak vrátit XML z ASPX v ASP.NET 1.1

Zápis výstupu XML na webovou stránku ASP.NET

Jak se vám výstup XML z ASP.NET?

Vytvoření obslužného programu ASHX v ASP.NET

54
Ian Boyd

Našel jsem správný způsob, jak vrátit XML klientovi v ASP.NET. Domnívám se, že když poukazuji na špatné cesty, bude to zřetelnější.

Nesprávné:

Response.Write(doc.ToString());

Nesprávné:

Response.Write(doc.InnerXml);

Nesprávné:

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

Opravit:

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)

Použijte TextWriter

Použít ne použít Response.OutputStream

Do použít Response.Output

Oba jsou toky, ale Output je TextWriter . Když se soubor XmlDocument uloží do souboru TextWriter, použije příkaz encoding zadaný tímto nástrojem TextWriter. XmlDocument automaticky změní uzel prohlášení xml tak, aby odpovídal kódování používanému nástrojem TextWriter. např. v tomto případě uzel deklarace XML:

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

stal by se

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

Důvodem je, že TextWriter byl nastaven na UTF-8. (Více o tom v okamžiku). Když je TextWriter vložen do znakových dat, zakóduje ho pomocí bajtových sekvencí vhodných pro jeho kódování.

Nesprávné:

doc.Save(Response.OutputStream);

V tomto příkladu je dokument nesprávně uložen do výstupu OutputStream, který neprovádí žádnou změnu kódování, a nemusí odpovídat zadanému kódování kódování uzlu odezvy nebo deklaraci uzlu deklarace XML.

Opravit

doc.Save(Response.Output);

Dokument XML je správně uložen do objektu TextWriter, což zajišťuje správné zpracování kódování.


Nastavit kódování

Kódování zadané klientovi v záhlaví:

Response.ContentEncoding = ...

musí odpovídat kódování dokumentu XML:

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

musí odpovídat skutečnému kódování přítomnému v byte sekvencích odeslaných klientovi. Aby všechny tyto tři věci souhlasily, nastavte jeden řádek:

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

Když je kódování nastaveno na objekt Response, nastaví stejné kódování na TextWriter. Sada kódování TextWriter způsobí, že XmlDocument změní deklaraci xml:

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

když je dokument uložen:

doc.Save(someTextWriter);

Uložit do odezvy Výstup

Nechcete dokument uložit do binárního proudu nebo napsat řetězec:

Nesprávné:

doc.Save(Response.OutputStream);

Zde je XML nesprávně uložen do binárního toku. Konečná sekvence kódování bajtů neodpovídá deklaraci XML nebo kódování obsahu webového serveru.

Nesprávné:

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

Zde je XML nesprávně převeden na řetězec, který nemá kódování. Uzel deklarace XML není aktualizován, aby odrážel kódování odpovědi, a odpověď není správně kódována, aby odpovídala kódování odpovědi. Také ukládání XML do mezilehlého řetězce ztrácí paměť.

Chcete nechcete uložit XML na řetězec, nebo XML zapsat do řetězce a response.Write řetězec, protože:

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

Do použití doc.Save(Response.Output);

Použít ne použít doc.Save(Response.OutputStream);

Použít ne použít Response.Write(doc.ToString());

Do not použijte 'Response.Write (doc.InnerXml);


Nastavte typ obsahu

ContentType Response musí být nastaven na "text/xml". Pokud tomu tak není, klient neví, že odesíláte XML.

Konečná odpověď

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

Kompletní příklad

Rob Kennedy měl dobrý názor, že jsem nezahrnul příklad start-to-finish.

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; } }
}
63
Ian Boyd

Níže je způsob, jakým handler vrátí data o proudu, která budou obsahovat xml data na straně serveru.  

Zde je kód obsluhy, který by data vrátil.

    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
Sheo Dayal Singh

Jsem překvapen, že se zdá, že se nikdo nikdy nezmínil o tom, že můžete použít XDocument/XElement, které jsou k dispozici v .NET 4.0 a usnadňují výstup XML.

0
Peter Bromberg
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();

Vypadá to, jako by zde bylo alespoň 10 otázek, pár bodů. 

Response.Clear - to opravdu záleží na tom, co jiného se děje v aplikaci - pokud máte httpmodules brzy v potrubí, které by mohly být psaní věci nechcete - pak vyčistit. Vyzkoušejte to a zjistěte. Šumař nebo Wireshark pro to užiteční.

Obsah Typ na text/xml - yup - dobrý nápad - přečtěte si na HTTP spec, proč je to důležité. IMO kdokoliv, kdo dělá webovou práci, měl alespoň jednou přečíst verzi 1.0 a 1.1. 

Kódování - jak je vaše kódování xml - pokud je to utf-8, pak to řekněte, pokud ne, řekněte něco jiného vhodného, ​​jen se ujistěte, že všechny odpovídají. 

Page - osobně by používal ashx nebo httpmodule, pokud používáte stránku, a chcete ji o něco rychlejší, zbavte se autoeventwireup a manuálně vázejte obsluhy událostí. 

Nejspíš by to bylo trošku plýtvání paměti, aby se xml mohl nejprve vypustit do řetězce, ale záleží hodně na velikosti xml, zda si toho všimnete. 

Jak navrhli jiní, ukládání xml do výstupního proudu je pravděpodobně nejrychlejší, normálně bych to udělal, ale pokud si nejste jisti, otestujte jej, nespoléhejte se na to, co čtete na interwebu. Nevěřte jen tomu, co říkám.

Pro jiný přístup, pokud xml to moc nemění, můžete ho jednoduše zapsat na disk a sloužit soubor přímo, což by bylo pravděpodobně docela výkonné, ale stejně jako všechno v programování, záleží ... 

0
seanb

Níže je uveden příklad správného způsobu, jakým si myslím. Alespoň to je to, co používám. Musíte udělat Response.Clear, abyste se zbavili záhlaví, která jsou již obsazena. Musíte předat správný ContentType textu/xml. Tímto způsobem sloužíte xml. Obecně chcete sloužit jako znaková sada UTF-8, protože to je to, co většina analyzátorů očekává. Ale nemyslím si, že to tak musí být. Pokud ji však změníte, ujistěte se, že jste změnili své prohlášení o XML dokumentu a označili tam znakovou sadu. A aby to správně zakódovalo vaše xml data v 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
Will Rickards