Utilizzo di StringWriter per la serializzazione XML

Attualmente sto cercando un modo semplice per serializzare oggetti (in C # 3).

Ho cercato su Google alcuni esempi e ho trovato qualcosa del tipo:

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()); 

Dopo aver letto questa domanda mi sono chiesto, perché non usare StringWriter? Sembra molto più facile.

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

Un altro problema era che il primo esempio generato XML I non poteva semplicemente scrivere in una colonna XML di SQL Server 2005 DB.

La prima domanda è: c’è una ragione per cui non dovrei usare StringWriter per serializzare un object quando ne ho bisogno in seguito come stringa? Non ho mai trovato un risultato utilizzando StringWriter durante la ricerca su google.

Il secondo è, naturalmente: se non dovessi farlo con StringWriter (per qualsiasi ragione), quale sarebbe un modo corretto e corretto?


aggiunta:

Come è già stato menzionato da entrambe le risposte, approfondirò ulteriormente il problema da XML a DB.

Durante la scrittura sul database ho ottenuto la seguente eccezione:

System.Data.SqlClient.SqlException: analisi XML: riga 1, carattere 38, imansible passare alla codifica

Per stringa

  

Ho preso la stringa creata da XmlTextWriter e l’ho messa lì come xml. Questo non ha funzionato (né con l’inserimento manuale nel DB).

Successivamente ho provato l’inserimento manuale (scrivendo semplicemente INSERT INTO …) con encoding = “utf-16” che ha anche fallito. Rimozione della codifica totalmente funzionante quindi. Dopo quel risultato sono tornato al codice StringWriter e voilà – ha funzionato.

Problema: non capisco davvero perché.

a Christian Hayter: Con quei test non sono sicuro di dover usare utf-16 per scrivere sul DB. Non impostare la codifica su UTF-16 (nel tag xml) allora?

Quando serializzi un documento XML su una stringa .NET, la codifica deve essere impostata su UTF-16. Le stringhe sono memorizzate come UTF-16 internamente, quindi questa è l’unica codifica che ha senso. Se si desidera memorizzare i dati in una codifica diversa, utilizzare invece una matrice di byte.

SQL Server funziona su un principio simile; qualsiasi stringa passata in una colonna xml deve essere codificata come UTF-16. SQL Server rifiuterà qualsiasi stringa in cui la dichiarazione XML non specifica UTF-16. Se la dichiarazione XML non è presente, lo standard XML richiede che sia impostato su UTF-8, quindi anche SQL Server lo rifiuterà.

Tenendo presente questo, ecco alcuni metodi di utilità per fare la conversione.

 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 è che di default non ti permette di impostare la codifica che pubblicizza , così puoi finire con un documento XML che pubblicizza la codifica come UTF-16, il che significa che devi codificarlo come UTF-16 se lo scrivi in ​​un file. Ho una piccola class per aiutare in questo però:

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

O se hai solo bisogno di UTF-8 (che è tutto ciò di cui ho spesso bisogno):

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

Per quanto riguarda il motivo per cui non è ansible salvare il tuo XML nel database: dovrai fornirci maggiori dettagli su ciò che è accaduto quando hai provato, se vuoi che siamo in grado di diagnosticare / risolvere il problema.

Prima di tutto, attenti a trovare vecchi esempi. XmlTextWriter hai trovato uno che utilizza XmlTextWriter , che è deprecato da .NET 2.0. Dovrebbe essere usato XmlWriter.Create .

Ecco un esempio di serializzazione di un object in una colonna 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; } 

Potrebbe essere stato trattato altrove, ma semplicemente cambiando la riga di codifica del sorgente XML in “utf-16” è ansible inserire l’XML in un tipo di dati xml di 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(); } } 

Il risultato è che tutto il testo XML è inserito nel campo del tipo di dati ‘xml’ ma la riga ‘intestazione’ viene rimossa. Quello che vedi nel record risultante è giusto

  

L’uso del metodo di serializzazione descritto nella voce “Risposta” è un modo di includere l’intestazione originale nel campo objective, ma il risultato è che il testo XML rimanente è racchiuso in un XML .

L’adattatore da tavolo nel codice è una class creata automaticamente utilizzando Visual Studio 2013 “Aggiungi nuova origine dati: procedura guidata”. I cinque parametri del metodo Inserisci vengono associati ai campi in una tabella di SQL Server.