Sérialisation d’un object en XML UTF-8 dans .NET

L’élimination correcte des objects est supprimée pour des raisons de brièveté, mais je suis choqué si c’est le moyen le plus simple d’encoder un object en UTF-8 en mémoire. Il doit y avoir un moyen plus facile, n’est-ce pas?

var serializer = new XmlSerializer(typeof(SomeSerializableObject)); var memoryStream = new MemoryStream(); var streamWriter = new StreamWriter(memoryStream, System.Text.Encoding.UTF8); serializer.Serialize(streamWriter, entry); memoryStream.Seek(0, SeekOrigin.Begin); var streamReader = new StreamReader(memoryStream, System.Text.Encoding.UTF8); var utf8EncodedXml = streamReader.ReadToEnd(); 

Votre code n’obtient pas l’UTF-8 en mémoire lorsque vous le relisez dans une chaîne, donc ce n’est plus dans UTF-8, mais dans UTF-16 (mais idéalement, il vaut mieux considérer les chaînes à un niveau supérieur). tout codage, sauf si forcé de le faire).

Pour obtenir les octets UTF-8, vous pouvez utiliser:

 var serializer = new XmlSerializer(typeof(SomeSerializableObject)); var memoryStream = new MemoryStream(); var streamWriter = new StreamWriter(memoryStream, System.Text.Encoding.UTF8); serializer.Serialize(streamWriter, entry); byte[] utf8EncodedXml = memoryStream.ToArray(); 

J’ai laissé de côté la même disposition que vous avez laissée. Je privilégie légèrement le suivant (avec mise au rebut normale):

 var serializer = new XmlSerializer(typeof(SomeSerializableObject)); using(var memStm = new MemoryStream()) using(var xw = XmlWriter.Create(memStm)) { serializer.Serialize(xw, entry); var utf8 = memStm.ToArray(); } 

Ce qui est à peu près la même complexité, mais montre qu’à chaque étape, il ya un choix raisonnable de faire autre chose, le plus pressant étant de se sérialiser dans un endroit autre que la mémoire, comme un fichier, TCP / IP. stream, firebase database, etc. Dans l’ensemble, ce n’est pas vraiment verbeux.

Non, vous pouvez utiliser un SsortingngWriter pour vous débarrasser du MemoryStream intermédiaire. Cependant, pour le forcer en XML, vous devez utiliser un SsortingngWriter qui remplace la propriété Encoding :

 public class Utf8SsortingngWriter : SsortingngWriter { public override Encoding Encoding => Encoding.UTF8; } 

Ou si vous n’utilisez pas encore C # 6:

 public class Utf8SsortingngWriter : SsortingngWriter { public override Encoding Encoding { get { return Encoding.UTF8; } } } 

Alors:

 var serializer = new XmlSerializer(typeof(SomeSerializableObject)); ssortingng utf8; using (SsortingngWriter writer = new Utf8SsortingngWriter()) { serializer.Serialize(writer, entry); utf8 = writer.ToSsortingng(); } 

Evidemment, vous pouvez faire d’ Utf8SsortingngWriter dans une classe plus générale qui accepte n’importe quel encodage dans son constructeur – mais selon mon expérience, UTF-8 est de loin le codage “personnalisé” le plus couramment requirejs pour un SsortingngWriter 🙂

Maintenant, comme le dit Jon Hanna, ce sera toujours en UTF-16 en interne, mais vous allez probablement le transmettre à un autre moment, pour le convertir en données binarys … à ce stade, vous pouvez utiliser la chaîne ci-dessus, le convertir en octets UTF-8, et tout ira bien – parce que la déclaration XML spécifiera “utf-8” comme encodage.

EDIT: Un exemple court mais complet pour montrer ce travail:

 using System; using System.Text; using System.IO; using System.Xml.Serialization; public class Test { public int X { get; set; } static void Main() { Test t = new Test(); var serializer = new XmlSerializer(typeof(Test)); ssortingng utf8; using (SsortingngWriter writer = new Utf8SsortingngWriter()) { serializer.Serialize(writer, t); utf8 = writer.ToSsortingng(); } Console.WriteLine(utf8); } public class Utf8SsortingngWriter : SsortingngWriter { public override Encoding Encoding => Encoding.UTF8; } } 

Résultat:

   0  

Notez l’encodage déclaré de “utf-8” qui est ce que nous voulions, je crois.

Très bonne réponse en utilisant l’inheritance, n’oubliez pas de remplacer l’initialiseur

 public class Utf8SsortingngWriter : SsortingngWriter { public Utf8SsortingngWriter(SsortingngBuilder sb) : base (sb) { } public override Encoding Encoding { get { return Encoding.UTF8; } } } 

J’ai trouvé cet article de blog qui explique très bien le problème et définit différentes solutions:

Astuce: Forcer le codage UTF8 ou autre pour XmlWriter avec SsortingngBuilder

J’ai décidé que la meilleure façon de le faire est d’omettre complètement la déclaration XML en mémoire. Il s’agit en fait de UTF-16 à ce stade, mais la déclaration XML ne semble pas significative tant qu’elle n’a pas été écrite dans un fichier avec un codage particulier; et même alors, la déclaration n’est pas requirejse. Il ne semble pas briser la désérialisation, au moins.

Comme l’indique @Jon Hanna, cela peut être fait avec un XmlWriter créé comme ceci:

 XmlWriter writer = XmlWriter.Create (output, new XmlWriterSettings() { OmitXmlDeclaration = true });