问题
I'm having trouble using the System.Runtime.Serialization.Json.DataContractJsonSerializer class to deserialize DateTime instances contained within a List<object>
. I cannot seem to get DateTime to deserialize back into the original type. The DataContractJsonSerializer
always deserializes it into a string type with the format "/Date(1329159196126-0500)/"
. It'll serialize and deserialize fine if I run it through using a strongly typed List<DateTime>
, however I am looking for way to get the serializer to identify and properly deserialize DateTimes when encountered within a simple list or array of object
.
Note that DateTimes are the only type besides primitives and strings that this list will ever contain. Here is the code snippet I'm using to test this.
var list = new List<object> { 27, "foo bar", 12.34m, true, DateTime.Now };
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>;
}
回答1:
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;
}
}
回答2:
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")
});
回答3:
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
回答4:
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]);
}
来源:https://stackoverflow.com/questions/9266435/datacontractjsonserializer-deserializing-datetime-within-listobject