.NET ServiceModel.Syndication - Изменение кодировки на RSS-канал - PullRequest
6 голосов
/ 28 марта 2011

Я пытаюсь устранить ошибку, из-за которой все RSS-каналы, которые я создаю на http://captainobvio.us, выдают следующую ошибку в Internet Explorer (версии 8 и 9):

Ошибка кода подачи. Переключение с текущей кодировки на указанную кодировку не поддерживается.Строка: 1 символ: 40

<?xml version="1.0" encoding="utf-16"?>

Проблема заключается в том, что фактический тип кодировки, отправляемый через заголовок HTTP, отличается от того, который декларируется в документе.Вот как выглядит мой код для записи вывода канала в 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);
        } 

А вот как выглядит мой код для фактического построения канала с использованием System.ServiceModel.Syndication в .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;

Я хотел бы изменить XML-документ на utf-8 вместо utf-16.Я также проверил пространство имен «Кодировка», чтобы выяснить, существует ли опция UTF16 (чтобы я мог исправить заголовок HTTP вместо документа XML), и не смог найти ее.

Существует ли простой способ изменитьАтрибут кодировки в XML-документе непосредственно из System.ServiceModel.Syndication?Какой самый простой способ исправить эту проблему?

1 Ответ

13 голосов
/ 28 марта 2011

Причина, по которой это происходит, заключается в том, что вы передаете StringBuilder в конструктор XmlWriter. Строки в .NET являются Unicode, поэтому XmlWriter предполагает utf-16, и вы не можете изменить это.

Таким образом, вы можете использовать поток вместо строителя строк, тогда вы можете управлять кодировкой с настройками:

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");
}

Все это, как говорится, гораздо лучше, больше MVCish, и я бы порекомендовал вам решение - написать 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);
        }
    }
}

и в вашем действии контроллера просто верните этот результат, чтобы не загромождать действия вашего контроллера соединительным кодом:

public ActionResult Index()
{
    var ideas = _repository.GetIdeas(0, 15).Ideas;
    var feed = _syndication.SyndicateIdeas(ideas);
    return new SyndicationResult(feed);
} 
...