2016-08-03 30 views
2

Ich habe eine große Sammlung von automatisch generierten Klassen, die serialisiert/deserialisiert aus XML mit .NET XmlSerializer. Einige dieser Klassen enthalten DateTime-Eigenschaften.Serialize DateTime zu XML in einem bestimmten Format. NET

Ich habe eine Anforderung zu serialisieren alle DateTime Eigenschaften mit bestimmten Format, zum Beispiel "u". :

System.DateTime.Now.ToString("u"); 
//returns something like "2008-06-15 21:15:07Z" 

Deserialize Methode scheint mit diesem Format zu arbeiten, aber der Serialisierung nicht - es gibt mir nur fest codiertes Format gleiches Format wie ich standardmäßig in dem Hosting-System habe (vielleicht kann ich die Serializer Trick durch Fadenwechsel Einstellung?) (Check Update # 1).

Hinweis: Ich habe bereits einige verwandte Fragen überprüft und sie werden durch Ändern der ursprünglichen Eigenschaften und Hinzufügen neuer geändert. Für mich ist es nicht akzeptabel, aufgrund der großen Anzahl von Änderungen, die ich machen müsste.

Unten ist ein Beispiel Testklasse, die ich um dieses Problem zu testen.

using System; 
using System.Linq; 
using System.Text; 
using System.Xml; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 
using System.Xml.Linq; 
using System.Xml.Serialization; 
using System.Globalization; 
using System.IO; 

namespace FunkyTests 
{ 
    [TestClass] 
    public class SerializationTests 
    { 
     [TestMethod] 
     public void FunkySerializationTest() 
     { 
      var date = DateTime.Now; 
      var dummy = new Dummy() { DummyProperty = date }; 
      var xml = SerializeToXml(dummy);//serializes with "o" format 

      var expected = date.ToString("u", new CultureInfo("en-US"));//in this example I want "u" format 
      var actual = XDocument.Parse(xml).Descendants("DummyProperty").Single().Value; 
      Assert.AreEqual(expected, actual); 
     } 

     [TestMethod] 
     public void FunkyDeserializationTest() 
     { 
      var date = DateTime.Now; 
      var dummy = new Dummy() { DummyProperty = date }; 
      var xml = SerializeToXml(dummy);//serializes with "o" format 
      var deserializedDummy = DeserializeFromXml<Dummy>(xml); 

      Assert.AreEqual(dummy.DummyProperty, deserializedDummy.DummyProperty); 
     } 

     private static T DeserializeFromXml<T>(string xml) 
     { 
      using (var textReader = new StringReader(xml)) 
      { 
       using (var reader = XmlReader.Create(textReader)) 
       { 
        var serializer = new XmlSerializer(typeof(T)); 
        var result = serializer.Deserialize(reader); 
        return (T)result; 
       } 
      } 
     } 

     private static string SerializeToXml<T>(T objectToSerialize) 
     { 
      var xml = new StringBuilder(); 
      using (var writer = XmlWriter.Create(xml, new XmlWriterSettings { OmitXmlDeclaration = true })) 
      { 
       var ns = new XmlSerializerNamespaces(); 
       ns.Add(string.Empty, string.Empty); 

       var serializer = new XmlSerializer(typeof(T)); 
       serializer.Serialize(writer, objectToSerialize, ns); 
      } 
      return xml.ToString(); 
     } 

     public class Dummy 
     { 
      public DateTime DummyProperty { get; set; } 
     } 
    } 
} 

Irgendwelche funky Ideen?

Update # 1: Ich dachte, dass Datum Serialisierung ist abhängig von Thread.CurrentCulture. Wenn ich XmlSerializer-Code richtig interpretiere, ist das Format fest codiert (Danke ILSpy).

// System.Xml.Serialization.XmlCustomFormatter 
internal static string FromDateTime(DateTime value) 
{ 
    if (XmlCustomFormatter.Mode == DateTimeSerializationSection.DateTimeSerializationMode.Local) 
    { 
     return XmlConvert.ToString(value, "yyyy-MM-ddTHH:mm:ss.fffffffzzzzzz"); 
    } 
    return XmlConvert.ToString(value, XmlDateTimeSerializationMode.RoundtripKind); 
} 

Update # 2: Ich habe eine Testmethode hinzugefügt, die Antwort von Alexander Petrov vorgeschlagenen Verwendungen. Es versagt bei der Behauptung von Ticks. Laut Serialize DateTime as binary Problem ist in Interna von DateTime und wird durch das Verlieren "Kind" von DateTime verursacht. Es wurde vorgeschlagen, DateTimeOffset zu verwenden, was zu einem anderen Serialisierungsproblem führt, das in How can I XML Serialize a DateTimeOffset Property?

+0

Siehe [dies] (http: // stackoverflow.com/q/3534525/1997232) (die Sie bereits erwähnt haben), sind Sie entweder auf 'XmlIgnoreAttribute' (mit einer anderen Eigenschaft von zB' string' Typ zu serialisieren/deserialisieren 'DateTime' Eigenschaft) oder' IXmlSerializable' (benutzerdefinierter Serializer, Hier können Sie eigene Attribute hinzufügen, über die Sie verschiedene Optionen für Serializer/Deserializer einschließlich Datenformat angeben können. Wenn Sie den kulturabhängigen 'XmlSerializer' finden (ich wette, es sollte einen geben), können Sie eine eigene Kultur mit dem benutzerdefinierten' DateTime'-Format erstellen und verwenden. – Sinatr

+0

Haben Sie Ihr Problem gelöst? –

Antwort

0

erläutert wird. Versuchen Sie benutzerdefinierte XML-Reader und Writer zu verwenden.

public class CustomDateTimeWriter : XmlTextWriter 
{ 
    public CustomDateTimeWriter(TextWriter writer) : base(writer) { } 
    public CustomDateTimeWriter(Stream stream, Encoding encoding) : base(stream, encoding) { } 
    public CustomDateTimeWriter(string filename, Encoding encoding) : base(filename, encoding) { } 

    public override void WriteRaw(string data) 
    { 
     DateTime dt; 

     if (DateTime.TryParse(data, out dt)) 
      base.WriteRaw(dt.ToString("u", new CultureInfo("en-US"))); 
     else 
      base.WriteRaw(data); 
    } 
} 

public class CustomDateTimeReader : XmlTextReader 
{ 
    public CustomDateTimeReader(TextReader input) : base(input) { } 
    // define other required constructors 

    public override string ReadElementString() 
    { 
     string data = base.ReadElementString(); 
     DateTime dt; 

     if (DateTime.TryParse(data, null, DateTimeStyles.AdjustToUniversal, out dt)) 
      return dt.ToString("o"); 
     else 
      return data; 
    } 
} 

Verwenden

var dummy = new Dummy { DummyProperty = DateTime.Now }; 
Console.WriteLine(dummy.DummyProperty); 
var xs = new XmlSerializer(typeof(Dummy)); 
string xml; 

using (var stringWriter = new StringWriter()) 
using (var xmlWriter = new CustomDateTimeWriter(stringWriter)) 
{ 
    xmlWriter.Formatting = Formatting.Indented; 

    xs.Serialize(xmlWriter, dummy); 
    xml = stringWriter.ToString(); 
} 

Console.WriteLine(xml); 

using (var stringReader = new StringReader(xml)) 
using (var xmlReader = new CustomDateTimeReader(stringReader)) 
{ 
    dummy = (Dummy)xs.Deserialize(xmlReader); 
    Console.WriteLine(dummy.DummyProperty); 
} 

Vorteile:

Dieser Ansatz automatisch (de) serialisiert alle Werte der Datum-Zeit zu/von dem gewünschten Format, ohne Änderungen an den generierten zu erfordern Klassen.

Nachteile:

Dieser Ansatz zufällig die Werte wie Datum-Zeit ändern können.

Dieser Ansatz kann die (De-) Serialisierung verlangsamen.

+0

Sorry, Sie warten zu halten. Ich habe meinen Test aktualisiert, um Ihre Serialisierungsmethode zu verwenden, und es schlägt mit einer seltsamen Nachricht fehl: Ergebnismeldung: \t Assert.AreEqual fehlgeschlagen. Erwartet: <2016-08-25 14:21:58>. Aktuell: <2016-08-25 14:21:58>. Höchstwahrscheinlich gibt es ein Problem mit Ticks. Ich werde das nachprüfen und dich informieren. – Sielu