ASP.NETでXMLを返すというタスクに対する多くの半分の解決策に遭遇しました。ただし、ほとんどの場合に機能するコードをやみくもにコピーアンドペーストしたくありません。 rightコードが必要で、whyが正しいことを知りたいです。批判が欲しい。情報が欲しい。知識が欲しい。理解してほしい。
以下は、複雑さを増す順序でのコードの断片であり、それぞれが引き起こすさらなる質問のいくつかを含む、私が見た部分的な解決策のいくつかを表し、ここで答えたいと思います。
徹底的な答えは、なぜmustが必要なのかmust notが以下の事柄のいずれか(---)を必要とするか、あるいはそれが無関係である理由を説明する必要があります。
最後に、次のようなヘルパー関数の内容を記述する必要があると想像してください。
///<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
はより堅牢になりますか?
HTMLを出力しないことを理解しているため、ashxを空白のaspxメインファイルと同じように使用していますか?
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();
}
それとも具体的にnotではないでしょうか?コンテンツタイプに文字セットがありますが、プロパティを設定しないと、サーバーが台無しになりますか?
他のコンテンツタイプ、たとえば:
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
に詰め込むよりも良いですか?もっと悪いの?前者はサポートされていますか?後者ですか?
実際にStringを書きたくありません。 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
を使用していることに注意してください。これはいいですか?悪い?いい?悪いですか?もっと早く?もっとゆっくり?より多くのメモリを消費しますか?メモリ集約度が低いですか?
I 読み取り レンダリングする必要がある
page_Load()を使用するときに発生するチャンク化の問題を回避するために、ページのRender()メソッドのXML。
チャンキングとは何ですか?チャンクの問題点は何ですか?また、Page_Render
を使用することでそれらを排除する方法は何ですか?
XmlDocument
オブジェクトの内容を文字列に書き込み、それを書き込みたくないのは、メモリを浪費するからです。つまり、これらのいずれかが悪いでしょう:
Response.Write(doc.ToString());
Response.Write(doc.InnerXml);
xmlWrite.WriteString(doc.ToString());
xmlWrite.WriteString(doc.InnerXml);
同様の質問
参考文献
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)
_
not使用_Response.OutputStream
_
Do use _Response.Output
_
どちらもストリームですが、Output
は TextWriter です。 XmlDocument
がTextWriterに自身を保存する場合、そのTextWriterで指定されたencodingを使用します。 XmlDocumentは、TextWriterが使用するエンコーディングに一致するように、xml宣言ノードを自動的に変更します。例えばこの場合、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に誤って保存され、エンコードの変更は行われず、応答のcontent-encodingまたはXML宣言ノードの指定されたエンコードと一致しない場合があります。
正しい
_doc.Save(Response.Output);
_
XMLドキュメントはTextWriterオブジェクトに正しく保存され、エンコードが適切に処理されます。
ヘッダーでクライアントに指定されたエンコード:
_Response.ContentEncoding = ...
_
xMLドキュメントのエンコーディングと一致する必要があります。
_<?xml version="1.0" encoding="..."?>
_
クライアントに送信されるバイトシーケンスに存在する実際のエンコーディングと一致する必要があります。これら3つすべてを一致させるには、次の1行を設定します。
_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を中間文字列に保存するとメモリが無駄になります。
do n'tは、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);
not use doc.Save(Response.OutputStream);
を実行します
not use Response.Write(doc.ToString());
を実行します
not use '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
_
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 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を使用するもう1つの正当な理由)。
XmlDocument
オブジェクトは、埋め込まれたencoding="..."
Response
のエンコード(例:UTF-8
)
Response.End()
あなたが本当にASPXでやる必要があるが、少し抜本的であれば、ASHXではそれをしないでください。
以下は、ハンドラーがサーバー側の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();
}
.NET 4.0で利用可能なXDocument/XElementを使用して、XMLをはるかに簡単に出力できることを誰も言及したことがないように思えます。
以下は、ハンドラを呼び出してストリームデータを受信し、xml docにロードするサーバー側コードです
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);
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();
ここでは、少なくとも10個の質問が1つにまとめられているようです。
Response.Clear-アプリで他に何が行われているかに本当に依存します-パイプラインの早い段階で不要なものを書いているかもしれないhttpmoduleがある場合は、それをクリアします。それをテストして調べてください。これに役立つFiddlerまたはWireshark。
Content Type to text/xml-はい-良いアイデア-これが重要である理由についてHTTP仕様を読んでください。 Webの作業を行うIMOのユーザーは、1.0および1.1の仕様を少なくとも1回読んでおく必要があります。
エンコード-xmlはどのようにエンコードされますか-utf-8である場合、そうである場合、そうでない場合は、適切な何かを言って、それらがすべて一致することを確認してください。
ページ-個人的には、ページを使用している場合はashxまたはhttpmoduleを使用し、少し速くしたい場合は、autoeventwireupを取り除き、イベントハンドラーを手動でバインドします。
最初にxmlを文字列にダンプするのは少しメモリを浪費するでしょうが、気づくかどうかはxmlのサイズに大きく依存します。
他の人が示唆しているように、おそらく最速でXMLを出力ストリームに保存すると、私は通常それを行いますが、よくわからない場合はテストし、インターウェブで読んだものに依存しないでください。私が言うことだけを信じないでください。
別のアプローチでは、xmlがそれほど変わらない場合は、ディスクに書き込むだけでファイルを直接提供できますが、これはかなりパフォーマンスが高い可能性がありますが、プログラミングのすべてのように、依存します...
以下は、私が考える正しい方法の例です。少なくとも私が使用するものです。 Response.Clearを実行して、すでに入力されているヘッダーを削除する必要があります。 text/xmlの正しいContentTypeを渡す必要があります。それが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
' -----------------------------------------------------------------------------