DataContractJsonSerializer – Deserialización de DateTime dentro de List

Tengo problemas para usar la clase System.Runtime.Serialization.Json.DataContractJsonSerializer para deserializar las instancias DateTime contenidas dentro de List . Parece que no puedo hacer que DateTime se deserialice nuevamente en el tipo original. DataContractJsonSerializer siempre lo deserializa en un tipo de cadena con el formato "/Date(1329159196126-0500)/" . Se serializará y deserializará bien si lo utilizo usando una List fuertemente tipada List ; sin embargo, estoy buscando la forma de que el serializador identifique y deserialice correctamente DateTimes cuando se encuentre dentro de una lista simple o matriz de object .

Tenga en cuenta que DateTimes es el único tipo además de las primitivas y cadenas que esta lista contendrá alguna vez. Aquí está el fragmento de código que estoy usando para probar esto.

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

Esto parece un comportamiento muy extraño, supongo que se debe a que DateTime no es un tipo que se reconoce en JSON. Sin embargo, puede desplegar su propio IDataContractSurrogate para modificar el proceso de serialización / deserialización.

Para usar esto, modifique su código de muestra cuando cree el serializador para esto:

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

Luego agrega esta clase:

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

En .NET Framework versión 4.5 el DataContractJsonSerializer tiene un constructor que acepta un objeto DataContractJsonSerializerSettings que se puede usar para establecer el DateTimeFormat :

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

Si DataContractJsonSerializer no es obligatorio , aquí hay una solución que usa Json.Net .

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

Esta es la cadena Json

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

y los tipos devueltos son long , string , double , bool y DateTime

Puede convertir DateTime.Now en una cadena antes de la serialización y
convertirlo a DateTime después de la deserialización.

Conversión a cadena por:

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

Conversión a DateTime después de la deserialización:

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

Entonces todo el código sería como:

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