2016-03-08 12 views
5

Unten ist die Eigenschaft in meinem Modell:Web Api 2 Datetime XML-Serialisierung Ausgabe

public DateTimeOffset AcquireDate { get; set; } 

Unten ist die Konfiguration in WebApiConfig:

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

Unten ist die JSON-Antwort (Datum liegt IS 8601 Format):

enter image description here

Im Folgenden finden Sie die XML respons 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> 

Von Fiedler:

enter image description here

In XML-Antwort, Datetime und Offset sind in zwei verschiedene Elemente zur Verfügung. Ich möchte DateTimeOffset als einzelnen Wert, genau wie JSON-Antwort (im ISO 8601-Format).

Ich könnte eine weitere Eigenschaft verwenden, die vom Typ string wäre, und auf diese Weise könnte mein Problem gelöst werden (leerer Setter erfordert, dass diese Eigenschaft serialisiert wird).

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

Jede andere Lösung abgesehen davon?

Die Lösung sollte keine Auswirkungen auf die vorhandene Json-Serialisierung haben, die einwandfrei funktioniert.

Antwort

2

Lassen Sie uns verstehen, dass DateTimeOffset Ihnen die UTC-Zeit gibt zusätzlich zu dem, wie viel dieser Wert von UTC abweicht. Somit identifiziert der Wert immer eindeutig einen einzelnen Zeitpunkt. Dies sind sehr wertvolle Informationen, die Sie nicht verlieren möchten. Wenn Sie jedoch aufgrund von Anforderungen nur den Offset speichern müssen, lesen Sie die Lösung weiter unten.

Da Sie Ihren Datentyp flexibel von DateTimeOffset in eine Zeichenfolge ändern können, können Sie den Typ möglicherweise etwas ändern und trotzdem DateTimeOffset verwenden.

Zum Beispiel

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

Ausgabe

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

Für JSON, brauchen wir einen Konverter, aber wir können Newtonsoft.Json.Converters wiederverwenden.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; 
     } 
    } 

Der Controller

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

Ausgabe

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

Voll Beispiel bei Github zu finden ist: https://github.com/alexnolasco/DatetimeOffsetXMLSerializationExample

01 auch

Siehe: How can I XML Serialize a DateTimeOffset Property?

Choosing Between DateTime, DateTimeOffset, TimeSpan, and TimeZoneInfo

+0

Wie würde ich es mit Web-API verwenden? Jedes Beispiel wäre hilfreich. –

+0

@NileshThakkar Eine Beispiel-APIController-Methode zu der Antwort hinzugefügt. Sehen Sie, ob das hilft. –

+0

Müssen wir Konfigurationsänderungen vornehmen, damit es für die Web API funktioniert? Da die Web-API standardmäßig DataContractSerializer für XMLMediaTypeFormatter verwendet. –