Это чувствует себя грязным. Но возможно это не... это в порядке для использования StringBuilder для записи XML? Мой инстинкт пищеварительного тракта говорит, "хотя это чувствует себя неправильным, это, вероятно, довольно проклятое производительный, потому что это не загружает дополнительные библиотеки, и наверху это не делает любых дополнительных вызовов метода, которые вызывает XmlWriter". Также кажется, что это - просто меньше кода в целом. Каково преимущество в XmlWriter?
Вот то, на что это похоже. Я создаю документ OpenSearch XML на основе домена, от которого Вы входите.
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/xml";
string domain = WebUtils.ReturnParsedSourceUrl(null); //returns something like www.sample.com
string cachedChan = context.Cache[domain + "_opensearchdescription"] as String;
if (cachedChan == null)
{
StringBuilder sb = new StringBuilder();
sb.Append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
sb.Append("<OpenSearchDescription xmlns=\"http://a9.com/-/spec/opensearch/1.1/\" xmlns:moz=\"http://www.mozilla.org/2006/browser/search/\">");
sb.Append(" <ShortName>Search</ShortName>");
sb.Append(" <Description>Use " + domain + " to search.</Description>");
sb.Append(" <Contact>contact@sample.com</Contact>");
sb.Append(" <Url type=\"text/html\" method=\"get\" template=\"http://" + domain + "/Search.aspx?q={searchTerms}\" />");
sb.Append(" <moz:SearchForm>http://" + domain + "/Search.aspx</moz:SearchForm>");
sb.Append(" <Image height=\"16\" width=\"16\" type=\"image/x-icon\">http://" + domain + "/favicon.ico</Image>");
sb.Append("</OpenSearchDescription>");
cachedChan = sb.ToString();
context.Cache.Insert(domain + "_opensearchdescription", cachedChan, null, DateTime.Now.AddDays(14), TimeSpan.Zero);
}
context.Response.Write(cachedChan);
}
Продолжение, ~2 года спустя я понял, что, что я означал говорить и полностью не удался сказать, это: каково преимущество ртов кода с помощью классов XML для генерации этого файла, по сравнению только с использованием строк? Есть ли один? Действительно ли это хуже, чем (например), пример John Saunder?
Я использовал метод Jim Schubert, выбирающий 'Я могу считать это, и он имеет смысл' вместо того, чтобы соперничать за 'правильность'. Я рад, что сделал. Нет ничего неправильно с примером John Saunder - но я чувствовал, что это был путь, властный для того, что я пытался выполнить. Прагматизм? Возможно.
Это очень неправильно. Используйте один из .NET API, который понимает XML, для написания XML.
Использование System.Xml.XmlWriter
не вызовет проблем с производительностью из-за загрузки «любых дополнительных библиотек».
Причина использования XML API заключается в том, что они понимают правила XML. Например, они будут знать набор символов, которые необходимо заключить в кавычки внутри элемента, и другой набор, который нужно заключить в кавычки внутри атрибута.
Это может не быть проблемой в вашем случае: возможно, вы уверены, что в домене
не будет никаких символов, которые нужно будет заключать в кавычки. В любой более широкой ситуации лучше всего позволить API XML выполнять XML - а они умеют это делать - чтобы вам не приходилось делать это самостоятельно.
Вот пример того, как легко создать действительный XML с помощью LINQ to XML:
public static string MakeXml()
{
XNamespace xmlns = "http://a9.com/-/spec/opensearch/1.1/";
XNamespace moz = "http://www.mozilla.org/2006/browser/search/";
string domain = "http://localhost";
string searchTerms = "abc";
var doc = new XDocument(
new XDeclaration("1.0", "UTF-8", "yes"),
new XElement(
xmlns + "OpenSearchDescription",
new XElement(xmlns + "ShortName", "Search"),
new XElement(
xmlns + "Description",
String.Format("Use {0} to search.", domain)),
new XElement(xmlns + "Contact", "contact@sample.com"),
new XElement(
xmlns + "Url",
new XAttribute("type", "text/html"),
new XAttribute("method", "get"),
new XAttribute(
"template",
String.Format(
"http://{0}/Search.aspx?q={1}",
domain,
searchTerms))),
new XElement(
moz + "SearchForm",
String.Format("http://{0}/Search.aspx", domain)),
new XElement(
xmlns + "Image",
new XAttribute("height", 16),
new XAttribute("width", 16),
new XAttribute("type", "image/x-icon"),
String.Format("http://{0}/favicon.ico", domain))));
return doc.ToString(); // If you _must_ have a string
}
Пожалуйста, не используйте StringBuilder. Любой, кто говорит вам, что это значительно быстрее, не предоставил вам никаких реальных данных. Разница в скорости несущественна, и впереди вас ждет кошмар ремонта.
ПОЗНАКОМЬТЕСЬ: StringBuilder vs XmlTextWriter
Ваша интуиция ошибочна. Независимо от того, пишете ли вы XML вручную или используете XmlWriter, наиболее эффективным способом отправки XML в HttpResponse будет добавление текста непосредственно в Response. Создание всей строки и последующая отправка тратит ресурсы впустую.
Вы можете создать сильно типизированный объект и использовать классы XmlSerialization для генерации данных xml
Ну, это тонко. Как и при любой другой оптимизации в жизни, вы нарушаете границы абстракции и платите за это цену, чтобы получить эффективность.
По моему опыту, это действительно значительно быстрее, не из-за загрузки библиотек, конечно (если что, это сделает его медленнее), а потому что это экономит на выделении строк. Я не помню точно, насколько быстрее, извините. Измерить это с помощью профилировщика будет сложно, потому что вы также экономите на сборке мусора.
Но не вините меня, когда вам придется иметь дело с кодировками, экранированием и черт знает чем еще, и не забудьте внимательно прочитать стандарт XML, прежде чем выпускать эти XML куда-либо.
Будут ли переменные домена возвращать символы "&" или другой символ, который необходимо закодировать? Вы можете потратить время на защитное программирование и проверить свой вклад.
Что ж, в написании XML-строк вручную нет ничего плохого, но это гораздо более подвержено ошибкам. Если у вас нет веских причин для повышения производительности (то есть вы измерили и обнаружили, что форматирование XML является узким местом), я бы вместо этого использовал классы XML. Вы сэкономите много времени на отладку и разработку.
Кстати, почему вы смешиваете динамические строковые операции с вызовами построителя? Вместо:
sb.Append(" <Description>Use " + domain + " to search.</Description>");
попробуйте следующее:
sb.Append(" <Description>Use ").Append(domain).Append(" to search.</Description>");
Я бы не стал использовать для этого StringBuilder, потому что вам нужно вызывать метод Append для каждой строки. Вы можете использовать XmlWriter, и это не повредит производительности.
Вы можете уменьшить объем генерируемого кода IL, выполнив следующие действия:
private const string XML_TEMPLATE = @"<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<OpenSearchDescription xmlns=\"http://a9.com/-/spec/opensearch/1.1/\" xmlns:moz=\"http://www.mozilla.org/2006/browser/search/\">
<ShortName>Search</ShortName>
<Description>Use {0} to search.</Description>
<Contact>contact@sample.com</Contact>
<Url type=\"text/html\" method=\"get\" template=\"http://{0}/Search.aspx?q={searchTerms}\" />
<moz:SearchForm>http://{0}/Search.aspx</moz:SearchForm>
<Image height=\"16\" width=\"16\" type=\"image/x-icon\">http://{0}/favicon.ico</Image>
</OpenSearchDescription>";
И в вашем методе:
if (cachedChan == null)
{
cachedChan = String.Format(XML_TEMPLATE, domain);
context.Cache.Insert(domain + "_opensearchdescription",
cachedChan, null, DateTime.Now.AddDays(14), TimeSpan.Zero);
}
Это должно хорошо сработать для вас, потому что метод, который у вас есть сейчас, должен будет создать новую строку для каждого вызова StringBuilder.Append (), затем вызовите этот метод. Вызов String.Format генерирует только 17 строк кода IL, по сравнению с StringBuilder, генерирующим 8 строк кода ctor, а затем 6 строк для каждого вызова Append. Хотя при сегодняшних технологиях лишние 50 строк IL не будут заметны.