问题描述
我使用以下类通过两个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进行序列化/反序列化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!