DataContractJsonSerializer - Deserializing DateTime within List<object>

后端 未结 4 660
情书的邮戳
情书的邮戳 2020-12-01 12:58

I\'m having trouble using the System.Runtime.Serialization.Json.DataContractJsonSerializer class to deserialize DateTime instances contained within a List

相关标签:
4条回答
  • 2020-12-01 13:47

    This seems like very strange behavior, my guess is that it stems from DateTime not being a type that is recongnized in JSON. However, you can roll your own IDataContractSurrogate to modify the serialization/deserialization process.

    To use this modify your sample code when you create the the serializer to this:

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

    Then add this 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<object> types
                if (obj.GetType() == typeof(List<object>))
                {
                    var objList = (List<object>)obj;
    
                    List<object> copyList = new List<object>(); // 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<Type> 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;
            }
        }
    
    0 讨论(0)
  • 2020-12-01 13:47

    You could convert DateTime.Now to a string before serialization and
    convert it back to DateTime after deserialization.

    Conversion to string by:

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

    Conversion back to DateTime after deserialization:

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

    So the whole code would be like:

      string dateAsString = Convert.ToString(DateTime.Now);
      var list = new object[] { 27, "foo bar", 12.34m, true, dateAsString };
    
      var serializer = new DataContractJsonSerializer(typeof (List<object>));
    
      using (MemoryStream ms = new MemoryStream())
      {
        serializer.WriteObject(ms, list);
        ms.Position = 0;
        var deserializedList = serializer.ReadObject(ms) as List<object>;
        DateTime dateTime = Convert.ToDateTime(deserializedList[4]);
      }
    
    0 讨论(0)
  • 2020-12-01 13:53

    If DataContractJsonSerializer isn't a must, here is a solution using Json.Net.

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

    This is the Json string

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

    and returned types are long,string,double,bool and DateTime

    0 讨论(0)
  • 2020-12-01 13:59

    In the .NET Framework version 4.5 the DataContractJsonSerializer has a constructor that accepts a DataContractJsonSerializerSettings object that can be used to set the DateTimeFormat:

    var ser = new DataContractJsonSerializer(typeof(CreateOmsEntryCommand),
                  new DataContractJsonSerializerSettings
                  {
                      DateTimeFormat = new DateTimeFormat("yyyy-MM-dd'T'HH:mm:ssZ")
                  });
    
    0 讨论(0)
提交回复
热议问题