2016-10-20 34 views
2

DateTime反序列化後,我想在中心位置做一些東西。所以我想把一個回調掛在合同上,但他們從來沒有被調用過。 任何想法?NewtonSoft JsonContract OnDeserializedCallbacks未調用原始類型?

public class MyContractResolver : DefaultContractResolver 
    { 
     protected override JsonContract CreateContract(Type objectType) 
     { 
      var result = base.CreateContract(objectType); 
      var primContract = result as JsonPrimitiveContract; 
      if (primContract != null && primContract.CreatedType == typeof(DateTime)) 
      { 
       primContract.OnDeserializingCallbacks.Add((o, context) => 
       { 
        var test = o; 
       }); 
       primContract.OnDeserializedCallbacks.Add((o, context) => 
       { 
        var test = o; 
       }); 
      } 
      return result; 
     } 
    } 

回調被添加,但從未調用。

回答

0

你是對的 - 我能夠重現這個(演示fiddle)。

即使陌生人,對於具有TypeConverter安裝(如System.Drawing.Color)等由JsonStringContract被處理非原始類型,則OnSerializingOnSerialized回調被調用,但不對應的反序列化回調。您可能需要report an issue

在此期間,你可以繼承IsoDateTimeConverter或一些其他轉換器從DateTimeConverterBase繼承並添加回調有:

public class MyContractResolver : DefaultContractResolver 
{ 
    protected override JsonContract CreateContract(Type objectType) 
    { 
     var result = base.CreateContract(objectType); 
     var primContract = result as JsonPrimitiveContract; 
     if (primContract != null 
      && (primContract.CreatedType == typeof(DateTime) || primContract.CreatedType == typeof(DateTime?)) 
      && primContract.Converter == null 
      ) 
     { 
      //Console.WriteLine("Adding {0} callbacks for {1}", primContract.ToString(), objectType.ToString()); 
      var converter = new MyIsoDateTimeConverter(); 
      converter.OnDeserializingCallbacks.Add((o, context) => 
      { 
       Console.WriteLine("Deserializing " + o); 
      }); 
      converter.OnDeserializedCallbacks.Add((o, context) => 
      { 
       Console.WriteLine("Deserialized " + o); 
      }); 
      primContract.Converter = converter; 
     } 
     return result; 
    } 
} 

class MyIsoDateTimeConverter : Newtonsoft.Json.Converters.IsoDateTimeConverter 
{ 
    private List<SerializationCallback> _onDeserializingCallbacks; 
    private List<SerializationCallback> _onDeserializedCallbacks; 

    public IList<SerializationCallback> OnDeserializingCallbacks 
    { 
     get 
     { 
      if (_onDeserializingCallbacks == null) 
      { 
       Interlocked.CompareExchange(ref _onDeserializingCallbacks, new List<SerializationCallback>(), null); 
      } 
      return _onDeserializingCallbacks; 
     } 
    } 

    public IList<SerializationCallback> OnDeserializedCallbacks 
    { 
     get 
     { 
      if (_onDeserializedCallbacks == null) 
      { 
       Interlocked.CompareExchange(ref _onDeserializedCallbacks, new List<SerializationCallback>(), null); 
      } 
      return _onDeserializedCallbacks; 
     } 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     var value = base.ReadJson(reader, objectType, existingValue, serializer); 
     if (value != null && value is DateTime) 
     { 
      if (_onDeserializingCallbacks != null) 
      { 
       foreach (var callback in _onDeserializingCallbacks) 
        callback(value, serializer.Context); 
      } 
      if (_onDeserializedCallbacks != null) 
      { 
       foreach (var callback in _onDeserializedCallbacks) 
        callback(value, serializer.Context); 
      } 
     } 

     return value; 
    } 
} 

需要注意的是,對於類型如DateTime具有值語義的,它不會使在構造對象之後但在填充對象之前調用OnDeserializing事件,因爲對象在構建時完全填充。因此我在反序列化之後調用了這兩個事件。

此外,通過Serializing Dates in JSON通讀,以確保IsoDateTimeConverter將滿足您的需求。

示例fiddle

+0

我想實現的是:我現在從我的rest api接收UTC日期時間(Kind = UTC)。我希望這些使用爲我的web應用程序的每個用戶配置的時區轉換爲本地日期時間。我想在中央位置這樣做。但正如你所指出的那樣,我不能在反序列化上做到這一點,因爲datetime已經在那裏構建,我不能返回一個新的實例。所以我認爲我需要創建一個轉換器,雖然我沒有使用默認的日期時間字符串語義。 –

+0

@JaapMosselman - 創建自己的'DateTime'轉換器並在'ReadJson()'末尾進行更改似乎是當時的方法。如果您需要幫助,可以提出另一個問題,因爲有關堆棧溢出問題的推薦格式是[每個帖子有一個問題](https://meta.stackexchange.com/questions/222735/can-i-ask-只有一個問題,每個崗位)。 – dbc