2016-03-08 20 views
5

Poniżej znajduje się nieruchomość w moim modelu:Web Api 2 datetimeoffset XML serializacji Issue

public DateTimeOffset AcquireDate { get; set; } 

Poniżej jest konfiguracja w WebApiConfig:

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

Poniżej jest odpowiedź JSON (data jest w IS 8601 format):

enter image description here

Poniżej jest respons XML e:

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

Od Skrzypek:

enter image description here

w XML odpowiedź, datetime i przesunięcia są dostępne w dwóch różnych elementów. Chcę DateTimeOffset jako pojedynczej wartości, podobnie jak odpowiedź json (w formacie ISO 8601).

Mogłabym użyć jeszcze jednej właściwości, która byłaby typu ciąg i w ten sposób mój problem mógłby zostać rozwiązany (seter pustych wymaga, aby ta właściwość była serializowana).

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

Jakieś inne rozwiązanie oprócz tego?

Rozwiązanie nie powinno wpływać na istniejącą serializację Json, która działa poprawnie.

Odpowiedz

2

Rozumiem, że DateTimeOffset podaje czas UTC oprócz tego, ile ta wartość różni się od UTC. W ten sposób wartość zawsze jednoznacznie identyfikuje jeden punkt w czasie. Jest to bardzo cenna informacja, której możesz nie chcieć stracić. Jeśli jednak ze względu na wymagania musisz przechowywać tylko przesunięcie, kontynuuj czytanie poniższego rozwiązania.

Ponieważ masz możliwość zmiany typu z DateTimeOffset na ciąg znaków, to możesz zmienić nieco typ i nadal używać DateTimeOffset.

Na przykład

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

Wyjście

<?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> 

Dla JSON, musimy konwertera ale możemy ponownie użyć 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; 
     } 
    } 

Sterownik

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

Wyjście

<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"}] 

Pełna przykładów można znaleźć na github: https://github.com/alexnolasco/DatetimeOffsetXMLSerializationExample

Zobacz także: How can I XML Serialize a DateTimeOffset Property?

Choosing Between DateTime, DateTimeOffset, TimeSpan, and TimeZoneInfo

+0

Jak bym go używać z Web API? Pomocny mógłby być każdy przykład. –

+0

@NileshThakkar Dodano przykładową metodę APIController do odpowiedzi, zobacz, czy to pomaga. –

+0

Czy musimy wprowadzić zmiany w konfiguracji, aby działało to w przypadku interfejsu Web API? Ponieważ Web API domyślnie używa DataContractSerializer dla XMLMediaTypeFormatter. –