如何使用DataContractJsonSerializer对存储在对象字段中的DateTime进行序列化/反序列化? [英] How to serialize/deserialize a DateTime stored inside an object field using DataContractJsonSerializer?
问题描述
我使用以下类通过两个ASP.NET服务交换JSON数据:
I use the following class to exchange JSON data over two ASP.NET services :
[DataContract]
public class Filter
{
[DataMember]
public string Name {get; set;}
[DataMember]
public FilterOperator Operator {get; set;}
[DataMember]
public object Value {get; set;}
}
这是问题所在:如果我在Value
中设置了DateTime
,它将被反序列化为字符串:
Here is the problem : if I set a DateTime
inside Value
, it will be deserialized as string :
Value = "/Date(1476174483233+0200)/"
这可能是因为解串器不知道最初进行序列化时该值的类型是什么:
This is probably because deserializer has no clue to know what was the type of the value when serialized initially :
JSON = {"Value":"\/Date(1476174483233+0200)\/"}
如此处所述,DataContractJsonSerializer
支持多态, __type
属性的帮助.
As explained here, DataContractJsonSerializer
supports polymorphism, with the help of the __type
property.
我试图在类的顶部添加[KnownType(typeof(DateTime))]
属性,但这无济于事.
I have tried to add [KnownType(typeof(DateTime))]
attribute on the top of the class but it does not help.
但是,如果我在Value
属性(以及类中相应的KnownType
属性)中设置了Tuple<DateTime>
,它将起作用(正确反序列化的值):
However if I set a Tuple<DateTime>
inside Value
property (and the appropriate KnownType
attribute on the class), it works (the value it deserialized properly) :
Value = {(10/11/2016 10:49:30 AM)}
在JSON内部,发出__type
Inside JSON, __type
is emited
JSON = {
"Value": {
"__type" : "TupleOfdateTime:#System",
"m_Item1" : "\/Date(1476175770028+0200)\/"
}
}
是否有一种方法可以强制DataContractJsonSerializer
发出适当的信息以正确地序列化/反序列化DateTime
(这意味着我在序列化后得到了DateTime
而不是字符串)?
Is there a way to force DataContractJsonSerializer
to emit proper information to serialize/deserialize DateTime
properly (which mean I got a DateTime
after serialization instead of a string) ?
我尝试在DataContractJsonSerializerSettings
中设置EmitTypeInformation = EmitTypeInformation.Always
,但这无济于事.
I have try to set EmitTypeInformation = EmitTypeInformation.Always
in DataContractJsonSerializerSettings
but it does not help.
推荐答案
问题在于,DataContractJsonSerializer
只为与JSON对象相对应的类型插入多态类型提示属性"__type"
-名称/值的无序集合被{
和}
包围的对.如果类型映射到其他任何内容(即JSON数组或原始类型),则没有位置可以插入类型提示.此限制记录在独立JSON序列化中:
The problem is that DataContractJsonSerializer
only inserts a polymorphic type hint property "__type"
for types that correspond to a JSON object - an unordered set of name/value pairs surrounded by {
and }
. If the type maps to anything else (i.e. a JSON array or primitive) then there is no place for a type hint to be inserted. This restriction is documented in Stand-Alone JSON Serialization:
类型提示仅适用于复杂类型
无法为非复杂类型发出类型提示.例如,如果某个操作具有Object返回类型但返回Circle,则JSON表示可以如前所示,并且类型信息被保留.但是,如果返回Uri,则JSON表示形式是一个字符串,并且用于表示Uri的字符串的事实也会丢失.这不仅适用于基本类型,而且适用于集合和数组.
There is no way to emit a type hint for non-complex types. For example, if an operation has an Object return type but returns a Circle, the JSON representation can be as shown earlier and the type information is preserved. However, if Uri is returned, the JSON representation is a string and the fact that the string used to represent a Uri is lost. This applies not only to primitive types but also to collections and arrays.
因此,您需要做的是修改您的Filter
类,以序列化和反序列化其值的通用代理对象,该对象封装了值的类型信息,并沿
Thus what you will need to do is to modify your Filter
class to serialized and deserialized a generic surrogate object for its value that encapsulates the value's type information, along the lines the one in this question for Json.Net:
[DataContract]
public class Filter
{
[DataMember]
public string Name { get; set; }
[DataMember]
public FilterOperator Operator { get; set; }
[IgnoreDataMember]
public object Value { get; set; }
[DataMember]
TypedSurrogate TypedValue
{
get
{
return TypedSurrogate.CreateSurrogate(Value);
}
set
{
if (value is TypedSurrogate)
Value = ((TypedSurrogate)value).ObjectValue;
else
Value = value;
}
}
}
[DataContract]
// Include some well-known primitive types. Other types can be included at higher levels
[KnownType(typeof(TypedSurrogate<string>))]
[KnownType(typeof(TypedSurrogate<bool>))]
[KnownType(typeof(TypedSurrogate<byte>))]
[KnownType(typeof(TypedSurrogate<sbyte>))]
[KnownType(typeof(TypedSurrogate<char>))]
[KnownType(typeof(TypedSurrogate<short>))]
[KnownType(typeof(TypedSurrogate<ushort>))]
[KnownType(typeof(TypedSurrogate<int>))]
[KnownType(typeof(TypedSurrogate<long>))]
[KnownType(typeof(TypedSurrogate<uint>))]
[KnownType(typeof(TypedSurrogate<ulong>))]
[KnownType(typeof(TypedSurrogate<float>))]
[KnownType(typeof(TypedSurrogate<double>))]
[KnownType(typeof(TypedSurrogate<decimal>))]
[KnownType(typeof(TypedSurrogate<DateTime>))]
[KnownType(typeof(TypedSurrogate<Uri>))]
[KnownType(typeof(TypedSurrogate<Guid>))]
[KnownType(typeof(TypedSurrogate<string[]>))]
public abstract class TypedSurrogate
{
protected TypedSurrogate() { }
[IgnoreDataMember]
public abstract object ObjectValue { get; }
public static TypedSurrogate CreateSurrogate<T>(T value)
{
if (value == null)
return null;
var type = value.GetType();
if (type == typeof(T))
return new TypedSurrogate<T>(value);
// Return actual type of subclass
return (TypedSurrogate)Activator.CreateInstance(typeof(TypedSurrogate<>).MakeGenericType(type), value);
}
}
[DataContract]
public class TypedSurrogate<T> : TypedSurrogate
{
public TypedSurrogate() : base() { }
public TypedSurrogate(T value)
: base()
{
this.Value = value;
}
public override object ObjectValue { get { return Value; } }
[DataMember]
public T Value { get; set; }
}
现在您的JSON将类似于:
Now your JSON will look something like:
{
"TypedValue": {
"__type": "TypedSurrogateOfdateTime:#Question39973917",
"Value": "/Date(1476244800000)/"
}
}
这篇关于如何使用DataContractJsonSerializer对存储在对象字段中的DateTime进行序列化/反序列化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!