2016-08-03 3 views
2

У меня есть большая коллекция автоматически сгенерированных классов, которые сериализуются/десериализуются из XML с помощью .NET XmlSerializer. Некоторые из этих классов содержат свойства DateTime.Сериализовать DateTime для XML в определенном формате .net

У меня есть требование для сериализации всех Свойства DateTime с использованием определенного формата, например, «u». :

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

метод Deserialize, кажется, работает с этим форматом, но сериализации не делает - он просто дает мне HARDCODED Отформатируй же формат, что у меня есть по умолчанию в системе хостинга (возможно, я могу обмануть сериалайзер путем изменения нити настройка?) (проверьте обновление №1).

Примечание: Я уже проверил несколько связанных вопросов, и они решены путем изменения оригинальных свойств и добавления новых. Для меня это неприемлемо из-за большого количества изменений, которые мне пришлось бы сделать.

Ниже приведен класс тестовый образец, который я использую, чтобы проверить эту проблему.

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

Любые идеи для фанки?

Обновление # 1: Я думал, что сериализация даты зависит от Thread.CurrentCulture. Если я правильно интерпретирую код XmlSerializer, формат жестко запрограммирован (спасибо 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: Я добавил метод тестирования, который использует предложенный ответ от Александра Петрова. Это не удается при утверждении Ticks. Согласно задаче Serialize DateTime as binary проблема во внутренних словах DateTime и вызвана потерей «Вид» DateTime. Было предложено использовать DateTimeOffset, что приводит к еще одной проблеме сериализации, поясняемой в How can I XML Serialize a DateTimeOffset Property?

+0

См. [This] (http: // stackoverflow.com/q/3534525/1997232) (вы уже упоминали), вы ограничены либо «XmlIgnoreAttribute» (используя другое свойство типа «string» для сериализации/десериализации свойства DateTime), либо «IXmlSerializable» (пользовательский сериализатор, где вы можете добавить собственные атрибуты, с помощью которых вы можете указать различные параметры для сериализатора/десериализатора, включая формат данных). Если вы можете найти зависящий от культуры «XmlSerializer» (я уверен, он должен быть один), тогда вы можете создать собственную культуру с пользовательским форматом 'DateTime' и использовать его. – Sinatr

+0

Вы решили проблему? –

ответ

0

Попробуйте использовать собственный читатель и писатель xml.

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

Применение

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

Преимущества:

Этот подход автоматически (де) сериализует все значения даты и времени в/из требуемого формата, без необходимости внесения изменений в генерируемый классы.

Недостатки:

Этот подход может случайно изменить значение, как дата-время.

Этот подход может замедлить сериализацию (де).

+0

Извините, что заставил вас ждать. Я обновил свой тест, чтобы использовать ваш метод сериализации, и он терпит неудачу со странным сообщением: Result Message: \t Ошибка Assert.AreEqual. Ожидается: <2016-08-25 14:21:58>. Фактически: <2016-08-25 14:21:58>. Скорее всего, есть проблема с Ticks. Я проверю и дам вам знать. – Sielu