DataContractJsonSerializer – Deserializing DateTime all’interno di List

Ho difficoltà a utilizzare la class System.Runtime.Serialization.Json.DataContractJsonSerializer per deserializzare le istanze DateTime contenute in un List . Non riesco a ottenere DateTime per deserializzare nuovamente nel tipo originale. DataContractJsonSerializer lo deserializza sempre in un tipo di stringa con il formato "/Date(1329159196126-0500)/" . Serializzerà e deserializzerà bene se lo eseguo usando un List fortemente tipizzato List , tuttavia sto cercando il modo di far sì che il serializzatore identifichi e deserializzi correttamente DateTimes quando lo si incontra all’interno di un semplice elenco o array di object .

Si noti che DateTimes è l’unico tipo oltre a primitive e stringhe che questo elenco conterrà mai. Ecco lo snippet di codice che sto usando per testarlo.

 var list = new List { 27, "foo bar", 12.34m, true, DateTime.Now }; var serializer = new DataContractJsonSerializer(typeof (List)); using (MemoryStream ms = new MemoryStream()) { serializer.WriteObject(ms, list); ms.Position = 0; var deserializedList = serializer.ReadObject(ms) as List; } 

Questo sembra un comportamento molto strano, la mia ipotesi è che deriva dal fatto che DateTime non è un tipo che viene riconosciuto in JSON. Tuttavia, è ansible eseguire il rollover del proprio IDataContractSurrogate per modificare il processo di serializzazione / deserializzazione.

Per utilizzare questo modifica il tuo codice di esempio quando crei il serializzatore su questo:

 var serializer = new DataContractJsonSerializer(typeof(List), null, int.MaxValue, false, new DateTimeDataContractSurrogate(), true); 

Quindi aggiungi questa class:

 public class DateTimeDataContractSurrogate : IDataContractSurrogate { private static readonly Regex dateRegex = new Regex(@"/Date\((\d+)([-+])(\d+)\)/"); private static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); public object GetCustomDataToExport(Type clrType, Type dataContractType) { // not used return null; } public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type dataContractType) { // not used return null; } public Type GetDataContractType(Type type) { // not used return type; } public object GetDeserializedObject(object obj, Type targetType) { // for debugging //Console.WriteLine("GetDeserializedObject: obj = {0} ({1}), targetType = {2}", obj, obj.GetType(), targetType); // only act on List types if (obj.GetType() == typeof(List)) { var objList = (List)obj; List copyList = new List(); // a list to copy values into. this will be the list returned. foreach (var item in objList) { string s = item as string; if (s != null) { // check if we match the DateTime format Match match = dateRegex.Match(s); if (match.Success) { // try to parse the string into a long. then create a datetime and convert to local time. long msFromEpoch; if (long.TryParse(match.Groups[1].Value, out msFromEpoch)) { TimeSpan fromEpoch = TimeSpan.FromMilliseconds(msFromEpoch); copyList.Add(TimeZoneInfo.ConvertTimeFromUtc(epoch.Add(fromEpoch), TimeZoneInfo.Local)); continue; } } } copyList.Add(item); // add unmodified } return copyList; } return obj; } public void GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection customDataTypes) { // not used } public object GetObjectToSerialize(object obj, Type targetType) { // for debugging //Console.WriteLine("GetObjectToSerialize: obj = {0} ({1}), targetType = {2}", obj, obj.GetType(), targetType); return obj; } public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData) { // not used return null; } public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit) { // not used return typeDeclaration; } } 

In .NET Framework versione 4.5 il DataContractJsonSerializer ha un costruttore che accetta un object DataContractJsonSerializerSettings che può essere utilizzato per impostare DateTimeFormat :

 var ser = new DataContractJsonSerializer(typeof(CreateOmsEntryCommand), new DataContractJsonSerializerSettings { DateTimeFormat = new DateTimeFormat("yyyy-MM-dd'T'HH:mm:ssZ") }); 

Se DataContractJsonSerializer non è un must , ecco una soluzione che utilizza Json.Net .

 var list = new List { 27, "foo bar", 12.34m, true, DateTime.Now }; string json = JsonConvert.SerializeObject(list); var orgObj=JsonConvert.DeserializeObject>(json); 

Questa è la stringa Json

 [27,"foo bar",12.34,true,"\/Date(1329161615596+0200)\/"] 

e i tipi restituiti sono long , string , double , bool e DateTime

È ansible convertire DateTime.Ora in una stringa prima della serializzazione e
convertirlo nuovamente in DateTime dopo la deserializzazione.

Conversione in stringa di:

 string dateAsString = Convert.ToString(DateTime.Now); 

Conversione indietro a DateTime dopo la deserializzazione:

 DateTime dateTime = Convert.ToDateTime(deserializedList[4]); 

Quindi l’intero codice sarebbe come:

  string dateAsString = Convert.ToString(DateTime.Now); var list = new object[] { 27, "foo bar", 12.34m, true, dateAsString }; var serializer = new DataContractJsonSerializer(typeof (List)); using (MemoryStream ms = new MemoryStream()) { serializer.WriteObject(ms, list); ms.Position = 0; var deserializedList = serializer.ReadObject(ms) as List; DateTime dateTime = Convert.ToDateTime(deserializedList[4]); }