Как вернуть XML в ASP.NET?
Я столкнулся с множеством полурешений для задачи возврата XML в ASP.NET. Я не хочу слепо копировать и вставлять код, который обычно работает большую часть времени; Я хочу правильный код, и я хочу знать, почему это так. Я хочу критики; Я хочу информацию; Я хочу знания; Я хочу понимания.
Ниже приведены fragmentы кода в порядке возрастания сложности, представляющие некоторые частичные решения, которые я видел, включая некоторые из дальнейших вопросов, которые каждый из них вызывает, и которые я хотел бы ответить здесь.
Тщательный ответ должен касаться того, почему мы должны иметь или не иметь ни одного из следующих факторов, или объяснить, почему это не имеет значения.
- Каковы наилучшие методы для версий XML-схем?
- в чем разница между json и xml
- Как обновить GridView?
- Как «выбрать» из XML с пространствами имен?
- Пример XML Parser DOM
- 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
В конце концов, представьте, что вам нужно написать содержимое вспомогательной функции следующим образом:
///Use this call inside your (Page_Xxx) method to write the ///xml to the web client. ///See for https://stackoverflow.com/questions/543319/how-to-return-xml-in-asp-net ///for proper usage. public static void ReturnXmlDocumentToWebClient( XmlDocument document, Page page) { ... }
Каждое появившееся решение начинается с того, что вы берете пустую страницу aspx и обрезаете весь HTML из переднего файла (что вызывает предупреждения в Visual Studio):
Затем мы используем событие Page_Load
для записи на выход:
protected void Page_Load(object sender, EventArgs e) { String xml = "Hello, world!"; Response.Write(xml); }
Нужно ли изменить ContentType на «text / xml» ? То есть:
protected void Page_Load(object sender, EventArgs e) { String xml = "Hello, world!"; Response.ContentType = "text/xml"; Response.Write(xml); }
Нужно ли нам сначала называть Response.Clear
?
protected void Page_Load(object sender, EventArgs e) { String xml = "Hello, world!"; Response.Clear(); Response.ContentType = "text/xml"; Response.Write(xml); }
Нужно ли нам это называть? Does not Response.Clear
сделать предыдущий шаг, чтобы убедиться, что код в переднем файле пуст (даже не пробел или возврат каретки) вне ненужным?
Does Response.Clear
делает его более надежным, если кто-то оставил пустую строку или пробел в файле кода?
Использует ashx так же, как пустой основной файл aspx, потому что понятно, что он не будет выводить HTML?
Нужно ли нам называть Response.End
? То есть:
protected void Page_Load(object sender, EventArgs e) { String xml = "Hello, world!"; 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 = "Hello, world!"; 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 = "Hello, world!"; 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
. Это хорошо? Плохо? Лучше? Хуже? Быстрее? Помедленнее? Больше памяти интенсивнее? Меньше памяти?
Я читал, что вы должны
XML в методе Render () страницы, чтобы избежать проблем с chunking, возникающих при использовании 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
- Сохранение ссылок на объекты при преобразовании XML с помощью XSLT?
- В чем разница между «или» и «|» при программировании в xslt?
- Как предотвратить внедрение XPath / XML в .NET.
- Доступ к @ атрибуту из SimpleXML
- XSLT не работает в веб-браузере
- Есть ли Java XML API, который может анализировать документ без разрешения объектов символов?
- JAXB: как отобразить карту в значение
- Есть ли свободные инструменты Xml Diff / Merge?
Я нашел правильный способ вернуть 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
Не используйте Response.OutputStream
Использовать Response.Output
Оба являются streamами, но Output
является TextWriter . Когда XmlDocument
сохраняет себя в TextWriter , он будет использовать кодировку, указанную этим TextWriter. XmlDocument автоматически изменит узел объявления xml в соответствии с кодировкой, используемой TextWriter. например, в этом случае узел объявления XML:
станет
Это связано с тем, что TextWriter настроен на UTF-8. (Еще об этом мгновенно). Поскольку TextWriter передается символьными данными, он будет кодировать его с помощью последовательностей байтов, соответствующих его кодировке.
Неправильно :
doc.Save(Response.OutputStream);
В этом примере документ неправильно сохраняется в OutputStream, который не выполняет никаких изменений в кодировке и может не соответствовать кодировке содержимого ответа или указанному кодированию узла объявления XML.
Верный
doc.Save(Response.Output);
Документ XML правильно сохраняется в объекте TextWriter, гарантируя правильную обработку кодировки.
Установить кодировку
Кодировка, предоставляемая клиенту в заголовке:
Response.ContentEncoding = ...
должен соответствовать кодировке XML-документа:
должен соответствовать фактической кодировке, присутствующей в последовательностях байтов, отправленных клиенту. Чтобы все три соглашения совпали, установите одну строку:
Response.ContentEncoding = System.Text.Encoding.UTF8;
Когда кодировка задана на объекте Response , она устанавливает ту же кодировку в TextWriter . Набор кодировки TextWriter заставляет XmlDocument изменять объявление xml :
когда документ сохранен:
doc.Save(someTextWriter);
Сохранить в ответ
Вы не хотите сохранять документ в двоичном streamе или писать строку:
Неправильно:
doc.Save(Response.OutputStream);
Здесь XML некорректно сохраняется в двоичном streamе. Конечная последовательность кодирования байтов не будет соответствовать объявлению 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
Используйте doc.Save(Response.Output);
Не используйте doc.Save(Response.OutputStream);
Не используйте 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 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, ie: * * 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("Rob Kennedy "); return doc; } public bool IsReusable { get { return false; } } }
В идеале вы должны использовать ashx для отправки XML, хотя я допускаю, чтобы код в ASPX перехватывал нормальное выполнение.
Response.Clear()
Я не использую это, если вы не уверены, что вы сбросили что-либо в ответ, уже нашли его и избавитесь от него.
Response.ContentType = "text/xml"
Определенно, обычный клиент не будет принимать контент как XML без этого типа контента.
Response.Charset = "UTF-8";
Пусть class ответа обрабатывает заголовок заголовка содержимого правильно. Используйте 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="..."
встроенного encoding="..."
кодировку Response
(например, UTF-8
)
Response.End()
Если вам действительно нужно в ASPX, но это немного радикально, в ASHX этого не делать.
Ниже приведен пример правильного пути, который я думаю. По крайней мере, это то, что я использую. Вам нужно выполнить 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 ' -----------------------------------------------------------------------------
Похоже, по крайней мере, 10 вопросов, включенных в один здесь, пару очков.
Response.Clear – это действительно зависит от того, что еще происходит в приложении – если у вас есть httpmodules в начале конвейера, который может писать ненужные материалы, а затем очистите его. Протестируйте его и узнайте. Для этого полезно использовать Fiddler или Wireshark.
Content Type to text / xml – yup – хорошая идея – прочитайте в спецификации HTTP о том, почему это важно. IMO, кто занимается веб-работой, должен хотя бы раз читать спецификации 1.0 и 1.1.
Кодирование – как ваш XML-код закодирован – если это utf-8, тогда скажите так, если нет, скажите что-то еще подходящее, просто убедитесь, что все они совпадают.
Страница – лично, будет использовать ashx или httpmodule, если вы используете страницу и хотите ее немного быстрее, избавитесь от autoeventwireup и привяжите обработчики событий вручную.
Вероятно, это будет пустой тратой памяти, чтобы сначала выгрузить xml в строку, но это зависит от размера xml, насколько вы заметили бы.
Как предложили другие, сохранение xml в выходной stream, вероятно, самый быстрый, я бы это сделал нормально, но если вы не уверены, протестируйте его, не полагайтесь на то, что вы читаете на interweb. Не просто верить всему, что я говорю.
Для другого подхода, если xml не так сильно изменится, вы можете просто записать его на диск и напрямую передать файл, что, скорее всего, будет довольно показательным, но, как и все в программировании, это зависит …
Я удивлен, что никто, кажется, никогда не упоминал, что вы можете использовать XDocument / XElement, которые доступны в .NET 4.0 и значительно упростить вывод XML.
Ниже приведен код на стороне сервера, который вызывается обработчиком и получает данные streamа и загружается в документ 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);
Ниже приведен способ, с помощью которого обработчик будет возвращать данные streamа, которые будут содержать XML-данные на стороне сервера.
Вот код обработчика, который возвращает данные.
public void ProcessRequest(HttpContext context) { StringBuilder xmlBuilder = new StringBuilder(); xmlBuilder.Append(""); xmlBuilder.Append(""); xmlBuilder.Append("Sheo"); xmlBuilder.Append(" "); xmlBuilder.Append(" "); context.Response.ContentType = "application/octet-stream"; context.Response.BinaryWrite(Encoding.UTF8.GetBytes(xmlBuilder.ToString())); context.Response.End(); }
Вы в основном ответили на все, и все уже, так что я не уверен, в чем дело?
FWIW Я бы использовал httphandler – кажется, нет смысла ссылаться на жизненный цикл страницы и иметь дело с отсечением бит viewstate и session и что у вас нет смысла для XML-документа. Это похоже на покупку автомобиля и снятие его на части, чтобы сделать ваш мотоцикл.
И контент-тип важен, так как запросчик знает, что делать с ответом.