2016-10-20 2 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, то OnSerializing и OnSerialized обратные вызовы называются, но не соответствующие обратные вызовы десериализации.

Возможно, вы захотите 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

Что я хочу достичь, так это: я получаю сейчас UTC datetimes (Kind = UTC) из моего остального api. Я хочу, чтобы они конвертировались в локальное datetime, используя часовой пояс, настроенный для пользователя моего веб-приложения. Я хочу сделать это в центральном месте. Но, как вы указали, я не могу сделать это при десериализации, потому что дата и время уже построены там, и я не могу вернуть новый экземпляр. Поэтому я думаю, что мне нужно создать конвертер, хотя я отлично разбираюсь в семантике строки datetime по умолчанию. –

+0

@JaapMosselman - Создание собственного конвертера 'DateTime' и внесение изменений в конце' ReadJson() ', казалось бы, было бы целесообразным. Если вам нужна помощь в этом, вы можете задать другой вопрос, так как рекомендуемый формат вопросов о переполнении стека - [один вопрос за сообщение] (https://meta.stackexchange.com/questions/222735/can-i-ask- только-один-вопрос-на-пост). – dbc