Rss20FeedFormatter Игнорирует тип TextSyndicationContent для SyndicationItem.Summary
При использовании класса Rss20FeedFormatter в проекте WCF я пытался обернуть содержимое моих элементов описания <![CDATA[ ]]>
раздел. Я обнаружил, что независимо от того, что я делал, HTML-содержимое элементов описания всегда кодировалось, а раздел CDATA никогда не добавлялся. Вглядываясь в исходный код Rss20FeedFormatter, я обнаружил, что при построении узла Summary он в основном создает новый экземпляр TextSyndicationContent, который стирает все параметры, которые были заданы ранее (я думаю).
Мой код
public class CDataSyndicationContent : TextSyndicationContent
{
public CDataSyndicationContent(TextSyndicationContent content)
: base(content)
{
}
protected override void WriteContentsTo(System.Xml.XmlWriter writer)
{
writer.WriteCData(Text);
}
}
... (следующий код должен обернуть резюме с разделом CDATA)
SyndicationItem item = new SyndicationItem();
item.Title = new TextSyndicationContent(name);
item.Summary = new CDataSyndicationContent(
new TextSyndicationContent(
"<div>This is a test</div>",
TextSyndicationContentKind.Html));
Rss20FeedFormatter Code(AFAIK, приведенный выше код не работает из-за этой логики)
...
else if (reader.IsStartElement("description", ""))
result.Summary = new TextSyndicationContent(reader.ReadElementString());
...
В качестве обходного пути я прибегнул к использованию RSS20FeedFormatter для создания RSS, а затем исправил RSS вручную. Например:
StringBuilder buffer = new StringBuilder();
XmlTextWriter writer = new XmlTextWriter(new StringWriter(buffer));
feedFormatter.WriteTo(writer ); // feedFormatter = RSS20FeedFormatter
PostProcessOutputBuffer(buffer);
WebOperationContext.Current.OutgoingResponse.ContentType =
"application/xml; charset=utf-8";
return new MemoryStream(Encoding.UTF8.GetBytes(buffer.ToString()));
...
public void PostProcessOutputBuffer(StringBuilder buffer)
{
var xmlDoc = XDocument.Parse(buffer.ToString());
foreach (var element in xmlDoc.Descendants("channel").First()
.Descendants("item")
.Descendants("description"))
{
VerifyCdataHtmlEncoding(buffer, element);
}
foreach (var element in xmlDoc.Descendants("channel").First()
.Descendants("description"))
{
VerifyCdataHtmlEncoding(buffer, element);
}
buffer.Replace(" xmlns:a10=\"http://www.w3.org/2005/Atom\"",
" xmlns:atom=\"http://www.w3.org/2005/Atom\"");
buffer.Replace("a10:", "atom:");
}
private static void VerifyCdataHtmlEncoding(StringBuilder buffer,
XElement element)
{
if (!element.Value.Contains("<") || !element.Value.Contains(">"))
{
return;
}
var cdataValue = string.Format("<{0}><![CDATA[{1}]]></{2}>",
element.Name,
element.Value,
element.Name);
buffer.Replace(element.ToString(), cdataValue);
}
Идея этого обходного пути возникла в следующем месте, я просто адаптировал его для работы с WCF вместо MVC. http://localhost:8732/Design_Time_Addresses/SyndicationServiceLibrary1/Feed1/
Мне просто интересно, если это просто ошибка в Rss20FeedFormatter или это по замыслу? Кроме того, если у кого-то есть лучшее решение, я хотел бы услышать это!
3 ответа
Ну, @Page Brooks, я рассматриваю это скорее как решение, чем как вопрос:). Спасибо!!! И чтобы ответить на ваш вопрос (;)), да, я определенно думаю, что это ошибка в Rss20FeedFormatter (хотя я не преследовал ее до сих пор), потому что столкнулся с точно такой же проблемой, которую вы описали.
У вас есть реферал localhost:8732 в вашем посте, но он не был доступен на моем локальном хосте;). Я думаю, что вы намеревались отдать должное обходному решению PostProcessOutputBuffer для этого поста: http://damieng.com/blog/2010/04/26/creating-rss-feeds-in-asp-net-mvc
Или на самом деле это не в этом посте, а в комментарии к нему Дэвида Уитни, который он позже изложил в отдельной статье: https://gist.github.com/davidwhitney/1027181
Спасибо за предоставленную адаптацию этого обходного пути больше к моим потребностям, потому что я тоже нашел обходной путь, но все еще боролся за адаптацию от MVC. Теперь мне нужно только настроить ваше решение, чтобы поместить RSS-канал в текущий запрос Http в обработчике.ashx, в котором я его использовал.
По сути, я предполагаю, что исправление, которое вы упомянули с использованием CDataSyndicationContent, относится к февралю 2011 года, при условии, что вы получили его из этого поста (по крайней мере, я это сделал): SyndicationFeed: Контент как CDATA?
Это исправление перестало работать в более новой версии ASP.NET или из-за того, что код Rss20FeedFormatter изменился на то, что вы указали в своем посте. Это изменение кода могло бы также быть улучшением для других вещей, которые есть в инфраструктуре MVC, но для тех, кто использует исправление CDataSyndicationContent, это определенно вызывает ошибку!
string stylesheet = @"<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform""><xsl:output cdata-section-elements=""description"" method=""xml"" indent=""yes""/></xsl:stylesheet>";
XmlReader reader = XmlReader.Create(new StringReader(stylesheet));
XslCompiledTransform t = new XslCompiledTransform(true);
t.Load(reader);
using (MemoryStream ms = new MemoryStream())
{
XmlWriter writer = XmlWriter.Create(ms, t.OutputSettings);
rssFeed.WriteTo(writer); // rssFeed is Rss20FeedFormatter
writer.Flush();
ms.Position = 0;
string niko = Encoding.UTF8.GetString(ms.ToArray());
}
Я уверен, что кто-то уже указал на это, но этот тупой обходной путь, который я использовал. Тип t.OutputSettings XmlWriterSettings с cdataSections заполняется одним "описанием" XmlQualifiedName.
Надеюсь, это поможет кому-то еще.
Я нашел код для Cdata в другом месте
public class CDataSyndicationContent : TextSyndicationContent
{
public CDataSyndicationContent(TextSyndicationContent content)
: base(content)
{
}
protected override void WriteContentsTo(System.Xml.XmlWriter writer)
{
writer.WriteCData(Text);
}
}
Код, чтобы назвать это что-то вроде:
item.Content = new Helpers.CDataSyndicationContent(new TextSyndicationContent("<span>TEST2</span>", TextSyndicationContentKind.Html));
Однако функция "WriteContentsTo" не вызывалась.
Вместо Rss20FeedFormatter я попробовал Atom10FeedFormatter - и все заработало! Очевидно, что это дает канал Atom, а не традиционный RSS - но стоит упомянуть.
Выходной код:
//var formatter = new Rss20FeedFormatter(feed);
Atom10FeedFormatter formatter = new Atom10FeedFormatter(feed);
using (var writer = XmlWriter.Create(response.Output, new XmlWriterSettings { Indent = true }))
{
formatter.WriteTo(writer);
}