2011-03-27 10 views
6

que estoy tratando de resolver un problema por el que todos los canales RSS que estoy produciendo a http://captainobvio.us producir el siguiente error en Internet Explorer (versiones 8 y 9):.NET ServiceModel.Syndication - Cambio de Codificación de RSS

Error de código de alimentación Cambiar de la codificación actual a la codificación especificada no compatible. Línea: 1 Título: 40

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

La cuestión es que el tipo de codificación real enviada a través de la cabecera HTTP es diferente a lo que declara el documento. Aquí es lo que mi código es el siguiente para escribir la salida de la alimentación a 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); 
     } 

Y aquí es lo que mi código es el de construir realmente la alimentación, utilizando System.ServiceModel.Syndication en .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; 

lo que me gustaría hacer es cambiar el documento XML para leer UTF-8 en lugar de UTF-16. También verifiqué el espacio de nombres de codificación para ver si había una opción UTF16 (para poder corregir el encabezado HTTP en lugar del documento XML) y no pude encontrar uno.

¿Hay una manera fácil de cambiar el atributo de codificación en el documento XML directamente desde System.ServiceModel.Syndication? ¿Cuál es la forma más fácil de solucionar este problema?

Respuesta

13

La razón por la que esto sucede es porque estás pasando un StringBuilder al constructor XmlWriter. Las cadenas en .NET son unicode, por lo que XmlWriter asume utf-16 y no puede modificar esto.

Así que se podría usar un chorro en lugar de constructor de cadena, entonces se puede controlar la codificación con los ajustes:

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

Dicho todo esto mucho mejor, más MVCish y uno del que os recomiendo solución es escribir un 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); 
     } 
    } 
} 

y en su acción de controlador simplemente volver este resultado por lo que no estorba su acciones del controlador con el código de plomería:

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

Darin, excelente respuesta. Ni siquiera pensé en mirar a StringBuilder como el origen del problema, y ​​su sugerencia de crear subclases de ActionResult es excelente. Si pudiera votarte más de una vez, lo haría. – Aaronontheweb

+0

@Aaronontheweb, me alegro de poder ayudar. –

Cuestiones relacionadas