【问题标题】:How to serialize/deserialize a DateTime stored inside an object field using DataContractJsonSerializer?如何使用 DataContractJsonSerializer 序列化/反序列化存储在对象字段中的 DateTime?
【发布时间】:2016-10-11 09:09:45
【问题描述】:

我使用以下类通过两个 ASP.NET 服务交换 JSON 数据:

[DataContract]
public class Filter
{
   [DataMember]
   public string Name {get; set;}

   [DataMember]
   public FilterOperator Operator {get; set;}

   [DataMember]
   public object Value {get; set;}    
}

问题来了:如果我在Value 中设置DateTime,它将被反序列化为字符串:

Value = "/Date(1476174483233+0200)/"

这可能是因为反序列化器在最初序列化时不知道值的类型:

JSON = {"Value":"\/Date(1476174483233+0200)\/"}

正如here 所解释的,DataContractJsonSerializer__type 属性的帮助下支持多态性。

我尝试在类的顶部添加[KnownType(typeof(DateTime))] 属性,但没有帮助。

但是,如果我在 Value 属性内设置一个 Tuple<DateTime>(以及类上的适当 KnownType 属性),它就可以工作(正确反序列化的值):

Value = {(10/11/2016 10:49:30 AM)}

在 JSON 内部,发出 __type

JSON = {
     "Value": {
        "__type" : "TupleOfdateTime:#System",
        "m_Item1" : "\/Date(1476175770028+0200)\/"
     }
}

有没有办法强制DataContractJsonSerializer 发出正确的信息以正确序列化/反序列化DateTime(这意味着我在序列化后得到DateTime 而不是字符串)?

我尝试在DataContractJsonSerializerSettings 中设置EmitTypeInformation = EmitTypeInformation.Always,但没有帮助。

【问题讨论】:

  • 可以修改Filter类吗?
  • 可以,可以改。

标签: c# asp.net json polymorphism datacontractjsonserializer


【解决方案1】:

问题在于DataContractJsonSerializer 只为对应于 JSON 对象的类型插入多态类型提示属性 "__type" - 一组由{} 包围的无序名称/值对。如果类型映射到其他任何东西(即 JSON 数组或原语),则没有地方可以插入类型提示。这个限制记录在Stand-Alone JSON Serialization:

类型提示仅适用于复杂类型

没有办法为非复杂类型发出类型提示。例如,如果操作具有 Object 返回类型但返回 Circle,则 JSON 表示可以如前所示并保留类型信息。但是,如果返回 Uri,则 JSON 表示是一个字符串,并且用于表示 Uri 的字符串的事实将丢失。这不仅适用于原始类型,也适用于集合和数组。

因此,您需要做的是修改您的 Filter 类以序列化和反序列化其值的通用代理对象,该对象封装了值的类型信息,类似于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 将如下所示:

{
  "TypedValue": {
    "__type": "TypedSurrogateOfdateTime:#Question39973917",
    "Value": "/Date(1476244800000)/"
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多