Usar StringWriter para la serialización XML

Actualmente estoy buscando una manera fácil de serializar objetos (en C # 3).

Busqué en Google algunos ejemplos y se me ocurrió algo como:

MemoryStream memoryStream = new MemoryStream ( ); XmlSerializer xs = new XmlSerializer ( typeof ( MyObject) ); XmlTextWriter xmlTextWriter = new XmlTextWriter ( memoryStream, Encoding.UTF8 ); xs.Serialize ( xmlTextWriter, myObject); string result = Encoding.UTF8.GetString(memoryStream .ToArray()); 

Después de leer esta pregunta, me pregunté, ¿por qué no usar StringWriter? Parece mucho más fácil.

 XmlSerializer ser = new XmlSerializer(typeof(MyObject)); StringWriter writer = new StringWriter(); ser.Serialize(writer, myObject); serializedValue = writer.ToString(); 

Otro problema fue que el primer ejemplo generado por XML no podía simplemente escribir en una columna XML de SQL Server 2005 DB.

La primera pregunta es: ¿Hay alguna razón por la que no deba usar StringWriter para serializar un Objeto cuando lo necesito como una cadena después? Nunca encontré un resultado usando StringWriter cuando busco en Google.

El segundo es, por supuesto: si no deberías hacerlo con StringWriter (por las razones que sean), ¿cuál sería una buena y correcta forma?


Adición:

Como ya se mencionó en ambas respuestas, entraré en el problema XML to DB.

Al escribir en la base de datos obtuve la siguiente excepción:

System.Data.SqlClient.SqlException: análisis XML: línea 1, carácter 38, no se puede cambiar la encoding

Para cuerda

  

Tomé la cadena creada desde XmlTextWriter y simplemente puse como xml allí. Éste no funcionó (ni con la inserción manual en el DB).

Luego probé la inserción manual (simplemente escribiendo INSERT INTO …) con encoding = “utf-16” que también falló. Eliminar la encoding funcionó totalmente entonces. Después de ese resultado cambié de nuevo al código de StringWriter y voilé, funcionó.

Problema: realmente no entiendo por qué.

en Christian Hayter: con esas pruebas no estoy seguro de tener que usar utf-16 para escribir en la base de datos. ¿No funcionaría entonces la configuración de la encoding a UTF-16 (en la etiqueta xml)?

Al serializar un documento XML en una cadena .NET, la encoding debe establecerse en UTF-16. Las cadenas se almacenan como UTF-16 internamente, por lo que esta es la única encoding que tiene sentido. Si desea almacenar datos en una encoding diferente, en su lugar utiliza una matriz de bytes.

SQL Server funciona con un principio similar; cualquier cadena que pase a una columna xml debe codificarse como UTF-16. SQL Server rechazará cualquier cadena donde la statement XML no especifique UTF-16. Si la statement XML no está presente, entonces el estándar XML requiere que sea de manera predeterminada a UTF-8, por lo que SQL Server también lo rechazará.

Teniendo esto en cuenta, aquí hay algunos métodos de utilidad para hacer la conversión.

 public static string Serialize(T value) { if(value == null) { return null; } XmlSerializer serializer = new XmlSerializer(typeof(T)); XmlWriterSettings settings = new XmlWriterSettings() { Encoding = new UnicodeEncoding(false, false), // no BOM in a .NET string Indent = false, OmitXmlDeclaration = false }; using(StringWriter textWriter = new StringWriter()) { using(XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings)) { serializer.Serialize(xmlWriter, value); } return textWriter.ToString(); } } public static T Deserialize(string xml) { if(string.IsNullOrEmpty(xml)) { return default(T); } XmlSerializer serializer = new XmlSerializer(typeof(T)); XmlReaderSettings settings = new XmlReaderSettings(); // No settings need modifying here using(StringReader textReader = new StringReader(xml)) { using(XmlReader xmlReader = XmlReader.Create(textReader, settings)) { return (T) serializer.Deserialize(xmlReader); } } } 

Un problema con StringWriter es que, de forma predeterminada , no le permite configurar la encoding que anuncia , por lo que puede terminar con un documento XML que anuncie su encoding como UTF-16, lo que significa que debe codificarlo como UTF-16 si lo escribes en un archivo Sin embargo, tengo una pequeña clase para ayudar con eso:

 public sealed class StringWriterWithEncoding : StringWriter { public override Encoding Encoding { get; } public StringWriterWithEncoding (Encoding encoding) { Encoding = encoding; } } 

O si solo necesitas UTF-8 (que es todo lo que a menudo necesito):

 public sealed class Utf8StringWriter : StringWriter { public override Encoding Encoding => Encoding.UTF8; } 

En cuanto a por qué no pudo guardar su XML en la base de datos, tendrá que darnos más detalles sobre lo que sucedió cuando lo intentó, si desea que podamos diagnosticarlo o corregirlo.

En primer lugar, tenga cuidado de encontrar ejemplos antiguos. Has encontrado uno que usa XmlTextWriter , que está en desuso desde .NET 2.0. XmlWriter.Create debería usarse en su lugar.

Aquí hay un ejemplo de serialización de un objeto en una columna XML:

 public void SerializeToXmlColumn(object obj) { using (var outputStream = new MemoryStream()) { using (var writer = XmlWriter.Create(outputStream)) { var serializer = new XmlSerializer(obj.GetType()); serializer.Serialize(writer, obj); } outputStream.Position = 0; using (var conn = new SqlConnection(Settings.Default.ConnectionString)) { conn.Open(); const string INSERT_COMMAND = @"INSERT INTO XmlStore (Data) VALUES (@Data)"; using (var cmd = new SqlCommand(INSERT_COMMAND, conn)) { using (var reader = XmlReader.Create(outputStream)) { var xml = new SqlXml(reader); cmd.Parameters.Clear(); cmd.Parameters.AddWithValue("@Data", xml); cmd.ExecuteNonQuery(); } } } } } 
 public static T DeserializeFromXml(string xml) { T result; XmlSerializerFactory serializerFactory = new XmlSerializerFactory(); XmlSerializer serializer =serializerFactory.CreateSerializer(typeof(T)); using (StringReader sr3 = new StringReader(xml)) { XmlReaderSettings settings = new XmlReaderSettings() { CheckCharacters = false // default value is true; }; using (XmlReader xr3 = XmlTextReader.Create(sr3, settings)) { result = (T)serializer.Deserialize(xr3); } } return result; } 

Puede haber sido cubierto en otra parte, pero el simple hecho de cambiar la línea de encoding de la fuente XML a ‘utf-16’ permite que el XML se inserte en un tipo de datos ‘xml’ de SQL Server.

 using (DataSetTableAdapters.SQSTableAdapter tbl_SQS = new DataSetTableAdapters.SQSTableAdapter()) { try { bodyXML = @"< ?xml version="1.0" encoding="UTF-8" standalone="yes"?>"; bodyXMLutf16 = bodyXML.Replace("UTF-8", "UTF-16"); tbl_SQS.Insert(messageID, receiptHandle, md5OfBody, bodyXMLutf16, sourceType); } catch (System.Data.SqlClient.SqlException ex) { Console.WriteLine(ex.Message); Console.ReadLine(); } } 

El resultado es que todo el texto XML se inserta en el campo de tipo de datos ‘xml’, pero se elimina la línea ‘encabezado’. Lo que ves en el registro resultante es solo

  

El uso del método de serialización descrito en la entrada “Contestado” es una forma de incluir el encabezado original en el campo de destino, pero el resultado es que el texto XML restante se incluye en una etiqueta XML .

El adaptador de tabla en el código es una clase construida automáticamente con el asistente de Visual Studio 2013 “Agregar origen de datos nuevos: los cinco parámetros del mapa Insertar método a campos en una tabla de SQL Server.