Вы правы - я смог воспроизвести это (демо 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.
Что я хочу достичь, так это: я получаю сейчас UTC datetimes (Kind = UTC) из моего остального api. Я хочу, чтобы они конвертировались в локальное datetime, используя часовой пояс, настроенный для пользователя моего веб-приложения. Я хочу сделать это в центральном месте. Но, как вы указали, я не могу сделать это при десериализации, потому что дата и время уже построены там, и я не могу вернуть новый экземпляр. Поэтому я думаю, что мне нужно создать конвертер, хотя я отлично разбираюсь в семантике строки datetime по умолчанию. –
@JaapMosselman - Создание собственного конвертера 'DateTime' и внесение изменений в конце' ReadJson() ', казалось бы, было бы целесообразным. Если вам нужна помощь в этом, вы можете задать другой вопрос, так как рекомендуемый формат вопросов о переполнении стека - [один вопрос за сообщение] (https://meta.stackexchange.com/questions/222735/can-i-ask- только-один-вопрос-на-пост). – dbc