.NET ServiceModel.Syndication - Changing Encoding on RSS Feed
I'm trying to solve a bug where all of the RSS feeds I'm producing at http://captainobvio.us produce the following error in Internet Explorer (versions 8 and 9):
Feed code error Switch from current encoding to specified encoding not supported. Line: 1 Character: 40
<?xml version="1.0" encoding="utf-16"?>
The issue is that the actual encoding type sent via the HTTP header is different than what the document declares. Here is what my code looks like for writing the feed's output to HTML:
public ContentResult Index()
{
var feed = _syndication.SyndicateIdeas(_repository.GetIdeas(0,15).Ideas);
var sb = new StringBuilder();
using (var writer = XmlWriter.Create(sb, new XmlWriterSettings { Encoding = Encoding.UTF8, NewLineHandling = NewLineHandling.Entitize, NewLineOnAttributes = true, Indent = true}))
{
feed.SaveAsRss20(writer);
writer.Close();
}
return Content(sb.ToString(), "application/rss+xml", Encoding.UTF8);
}
And here is what my code looks like for actually building the feed, using System.ServiceModel.Syndication in .NET 4.0:
var feed = new SyndicationFeed("CaptainObvio.us - Recent Ideas",
"The most recent ideas posted by the Community on CaptainObvio.us", new Uri("http://captainobvio.us/"), "CaptainObvio.us", new DateTimeOffset(ideas[0].DatePosted), items)
{
Generator = "CaptainObvio.us - http://captainobvio.us/"
};
return feed;
What I would like to do is change the 开发者_如何学CXML document to read utf-8 instead of utf-16. I also checked the Encoding namespace to see if there was a UTF16 option (so I could correct the HTTP header instead of the XML document) and wasn't able to find one.
Is there an easy way change the encoding attribute on the XML document directly from System.ServiceModel.Syndication? What's the easiest way to fix this issue?
The reason this happens is because you are passing a StringBuilder to the XmlWriter constructor. Strings in .NET are unicode so XmlWriter assumes utf-16 and you cannot modify this.
So you could use a stream instead of string builder, then you can control the encoding with the settings:
var settings = new XmlWriterSettings
{
Encoding = Encoding.UTF8,
NewLineHandling = NewLineHandling.Entitize,
NewLineOnAttributes = true,
Indent = true
};
using (var stream = new MemoryStream())
using (var writer = XmlWriter.Create(stream, settings))
{
feed.SaveAsRss20(writer);
writer.Flush();
return File(stream.ToArray(), "application/rss+xml; charset=utf-8");
}
All this being said a far better, more MVCish and a one the I would recommend you solution is to write a SyndicationResult
:
public class SyndicationResult : ActionResult
{
private readonly SyndicationFeed _feed;
public SyndicationResult(SyndicationFeed feed)
{
if (feed == null)
{
throw new HttpException(401, "Not found");
}
_feed = feed;
}
public override void ExecuteResult(ControllerContext context)
{
var settings = new XmlWriterSettings
{
Encoding = Encoding.UTF8,
NewLineHandling = NewLineHandling.Entitize,
NewLineOnAttributes = true,
Indent = true
};
var response = context.HttpContext.Response;
response.ContentType = "application/rss+xml; charset=utf-8";
using (var writer = XmlWriter.Create(response.OutputStream, settings))
{
_feed.SaveAsRss20(writer);
}
}
}
and in your controller action simply return this result so that you don't clutter your controller actions with plumbing code:
public ActionResult Index()
{
var ideas = _repository.GetIdeas(0, 15).Ideas;
var feed = _syndication.SyndicateIdeas(ideas);
return new SyndicationResult(feed);
}
精彩评论