2016-03-08 5 views
5

Ниже свойство в моей модели:Web Api 2 DateTimeOffset XML сериализации Выпуск

public DateTimeOffset AcquireDate { get; set; } 

Ниже конфигурация в WebApiConfig:

config.Formatters.Clear(); 
config.Formatters.Add(new JsonMediaTypeFormatter()); 
config.Formatters.Add(new XmlMediaTypeFormatter()); 

Ниже приводится ответ JSON (дата в IS 8601 формат):

enter image description here

Ниже в XML RESPONS е:

<AcquireDate xmlns:d3p1="http://schemas.datacontract.org/2004/07/System"> 
     <d3p1:DateTime>2008-01-10T16:40:12.1523923Z</d3p1:DateTime> 
     <d3p1:OffsetMinutes>330</d3p1:OffsetMinutes> 
</AcquireDate> 

От стельки:

enter image description here

В ответе Xml, дата и время и смещения доступны в двух различных элементах. Я хочу, чтобы DateTimeOffset как одно значение, точно так же как ответ json (в формате ISO 8601).

Я мог бы использовать еще одно свойство, которое будет иметь тип string, и таким образом моя проблема может быть решена (пустой сеттер требует, чтобы это свойство было сериализовано).

[DataMember(Name="AcquireDate")] 
    public string AcquireDateString 
    { 
     get 
     { 
      return AcquireDate.ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz"); 
     } 
     set { 
      AcquireDate = DateTimeOffset.Parse(value); 
     } 
    } 

Любое другое решение кроме этого?

Решение не должно влиять на существующую Json Serialization, которая работает нормально.

ответ

2

Давайте понимать, что DateTimeOffset дает вам время UTC в дополнение к тому, насколько это значение отличается от UTC. Таким образом, значение всегда однозначно идентифицирует одну точку во времени. Это очень ценная информация, которую вы, возможно, не захотите потерять. Но если из-за требований вы должны сохранить только смещение, то продолжайте читать ниже.

Поскольку у вас есть гибкость для изменения типа от DateTimeOffset до строки, возможно, вы можете немного изменить тип и использовать DateTimeOffset.

Например,

using System; 
using System.Xml; 
using System.Xml.Schema; 
using System.Xml.Serialization; 
using Newtonsoft.Json; 

namespace ConsoleApplication8 
{ 
    public struct Iso8601SerializableDateTimeOffset : IXmlSerializable 
    { 
     public DateTimeOffset value; 

     public Iso8601SerializableDateTimeOffset(DateTimeOffset value) 
     { 
      this.value = value; 
     } 

     public static implicit operator Iso8601SerializableDateTimeOffset(DateTimeOffset value) 
     { 
      return new Iso8601SerializableDateTimeOffset(value); 
     } 

     public static implicit operator DateTimeOffset(Iso8601SerializableDateTimeOffset instance) 
     { 
      return instance.value; 
     } 

     public static bool operator ==(Iso8601SerializableDateTimeOffset a, Iso8601SerializableDateTimeOffset b) 
     { 
      return a.value == b.value; 
     } 

     public static bool operator !=(Iso8601SerializableDateTimeOffset a, Iso8601SerializableDateTimeOffset b) 
     { 
      return a.value != b.value; 
     } 

     public static bool operator <(Iso8601SerializableDateTimeOffset a, Iso8601SerializableDateTimeOffset b) 
     { 
      return a.value < b.value; 
     } 

     public static bool operator >(Iso8601SerializableDateTimeOffset a, Iso8601SerializableDateTimeOffset b) 
     { 
      return a.value > b.value; 
     } 

     public override bool Equals(object o) 
     { 
      if (o is Iso8601SerializableDateTimeOffset) 
       return value.Equals(((Iso8601SerializableDateTimeOffset)o).value); 
      else if (o is DateTimeOffset) 
       return value.Equals((DateTimeOffset)o); 
      else 
       return false; 
     } 

     public override int GetHashCode() 
     { 
      return value.GetHashCode(); 
     } 

     public XmlSchema GetSchema() 
     { 
      return null; 
     } 

     public void ReadXml(XmlReader reader) 
     { 
      var text = reader.ReadElementString(); 
      value = DateTimeOffset.ParseExact(text, format: "o", formatProvider: null); 
     } 

     public override string ToString() 
     { 
      return value.ToString(format: "o"); 
     } 

     public string ToString(string format) 
     { 
      return value.ToString(format); 
     } 

     public void WriteXml(XmlWriter writer) 
     { 
      writer.WriteString(value.ToString(format: "o")); 
     } 
    } 

    public class Foo 
    { 
     public Guid Id { get; set; } 

     [JsonConverter(typeof(UtcDateTimeOffsetConverter))] 
     public Iso8601SerializableDateTimeOffset AcquireDate { get; set; } 
    } 


    class Program 
    { 
     static void Main(string[] args) 
     { 
      var foo = new Foo { 
       Id = Guid.NewGuid(), 
       AcquireDate = DateTimeOffset.Now 
      };   

      var xmlSerializer = new System.Xml.Serialization.XmlSerializer(foo.GetType()); 
      xmlSerializer.Serialize(Console.Out, foo); 
      Console.WriteLine(); 
      Console.ReadLine(); 
     } 
    } 
} 

Выход

<?xml version="1.0" encoding="IBM437"?> 
<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <Id>830cabe2-340b-42c6-bad4-12b5b8b1c43f</Id> 
    <AcquireDate>2016-03-14T10:47:51.8162249-04:00</AcquireDate> 
</Foo> 

Для JSON, нам нужен конвертер, но мы можем использовать Newtonsoft.Json.Converters.IsoDateTimeConverter

public class UtcDateTimeOffsetConverter : Newtonsoft.Json.Converters.IsoDateTimeConverter 
    { 
     public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
     { 
      if (value is Iso8601SerializableDateTimeOffset) 
      { 
       var date = (Iso8601SerializableDateTimeOffset)value; 
       value = date.value; 
      } 
      base.WriteJson(writer, value, serializer); 
     } 

     public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
     { 
      object value = base.ReadJson(reader, objectType, existingValue, serializer); 
      if (value is Iso8601SerializableDateTimeOffset) 
      { 
       var date = (Iso8601SerializableDateTimeOffset)value; 
       value = date.value; 
      } 
      return value; 
     } 
    } 

Контроллер

public class ValuesController : ApiController 
{ 
    public class Foo 
    { 
     public Guid Id { get; set; } 

     [JsonConverter(typeof(UtcDateTimeOffsetConverter))] 
     public Iso8601SerializableDateTimeOffset AcquireDate { get; set; } 
    } 

    // GET api/values 
    public IEnumerable<Foo> Get() 
    { 
     return new Foo[] { 
      new Foo() { 
       Id = Guid.NewGuid(), 
       AcquireDate = DateTimeOffset.Now 
      } 
     }; 
    } 
} 

Выход

<ArrayOfFoo xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/WebApplication1.Models"> 
    <Foo> 
     <AcquireDate>2016-03-14T12:04:30.2791167-04:00</AcquireDate> 
     <Id>b3188528-f854-454a-bf9f-9822ff27dc6f</Id> 
    </Foo> 
</ArrayOfFoo> 

JSON

[{"Id":"e24bc769-3463-4320-b39a-9ff97e709142","AcquireDate":"2016-03-15T10:47:29.3061449-04:00"}] 

Полный пример можно найти на GitHub: https://github.com/alexnolasco/DatetimeOffsetXMLSerializationExample

Смотрите также: How can I XML Serialize a DateTimeOffset Property?

Choosing Between DateTime, DateTimeOffset, TimeSpan, and TimeZoneInfo

+0

Как бы я использовать его с Web API? Любой пример был бы полезен. –

+0

@NileshThakkar Добавил в ответ образец метода APIController, посмотрим, поможет ли это. –

+0

Должны ли мы внести какие-либо изменения в конфигурацию, чтобы заставить его работать в Web API? Поскольку Web API по умолчанию использует DataContractSerializer для XMLMediaTypeFormatter. –

 Смежные вопросы

  • Нет связанных вопросов^_^