2016-03-08 1 views
5

Voici la propriété dans mon modèle:Web Api 2 Datetimeoffset sérialisation XML Edition

public DateTimeOffset AcquireDate { get; set; } 

Ci-dessous la configuration WebApiConfig:

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

est inférieure à la réponse JSON (date est dans IS 8601 format):

enter image description here

Ci-dessous les responsab 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> 

De violoniste:

enter image description here

En réponse XML, datetime et le décalage sont disponibles en deux éléments différents. Je souhaite que DateTimeOffset soit une valeur unique, tout comme la réponse json (au format ISO 8601).

Je pourrais utiliser une propriété de plus qui serait de type chaîne et ainsi mon problème pourrait être résolu (setter vide nécessite que cette propriété soit sérialisée).

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

Autre solution à part cela?

La solution ne devrait pas affecter la sérialisation Json existante qui fonctionne correctement.

Répondre

2

Nous allons comprendre que DateTimeOffset vous donne l'heure UTC en plus de combien cette valeur diffère de l'UTC. Ainsi, la valeur identifie toujours sans ambiguïté un seul point dans le temps. C'est une information très précieuse que vous ne voudrez peut-être pas perdre. Mais si, en raison d'exigences, vous ne devez stocker que le décalage, continuez à lire la solution ci-dessous.

Puisque vous avez la possibilité de changer votre type de DateTimeOffset en chaîne, alors peut-être vous pouvez modifier le type un peu et toujours utiliser DateTimeOffset.

Par exemple,

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

Sortie

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

Pour JSON, nous avons besoin d'un convertisseur, mais nous pouvons réutiliser 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; 
     } 
    } 

Le contrôleur

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

Sortie

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

Exemple complet se trouve à github: https://github.com/alexnolasco/DatetimeOffsetXMLSerializationExample

Voir aussi: How can I XML Serialize a DateTimeOffset Property?

Choosing Between DateTime, DateTimeOffset, TimeSpan, and TimeZoneInfo

+0

Comment pourrais-je l'utiliser avec l'API Web? Tout exemple serait utile. –

+0

@NileshThakkar Ajout d'un exemple de méthode APIController à la réponse, voir si cela aide. –

+0

Devons-nous apporter des modifications à la configuration pour que cela fonctionne pour l'API Web? Parce que l'API Web utilise par défaut DataContractSerializer pour XMLMediaTypeFormatter. –