Предпосылки:
Мне нужно сохранить шаблон даты/времени UTC DateTime в оба конца через REST-API на основе JSON.
string utcTimestamp = DateTime.UtcNow.ToString( "o" );
// 2018-11-27T22:35:32.1234567Z
Поэтому я написал себе DateTimeStringConverter
чтобы гарантировать, что информация о местной культуре не участвует
class DateTimeStringConverter:
JsonConverter<DateTime>
{
public override void WriteJson( JsonWriter writer, DateTime value, JsonSerializer serializer )
{
string convertedValue = value.ToString( "o" );
writer.WriteValue( convertedValue );
}
public override DateTime ReadJson( JsonReader reader, Type objectType, DateTime existingValue, bool hasExistingValue, JsonSerializer serializer )
{
string value = reader.Value.ToString( );
DateTime convertedValue = DateTime.Parse( value ).ToLocalTime( );
return convertedValue;
}
}
Я был очень смущен тем, почему я получаю объект DateTime
без миллисекунд. После долгих проб и ошибок я попал в это.
public override DateTime ReadJson( JsonReader reader, Type objectType, DateTime existingValue, bool hasExistingValue, JsonSerializer serializer )
{
Console.WriteLine( reader.Value.GetType( ).ToString( ) );
// System.DateTime
string value = reader.Value.ToString( );
DateTime convertedValue = DateTime.Parse( value ).ToLocalTime( );
return convertedValue;
}
JSON.Net предоставляет мне уже преобразованный объект DateTime для самостоятельной десериализации без каких-либо миллисекундных данных. Я не нашел никаких подсказок относительно того, является ли это ошибкой или функцией.
Чтобы проверить это, я написал BooleanStringConverter
.
class BoolStringConverter:
JsonConverter<bool>
{
public override void WriteJson( JsonWriter writer, bool value, JsonSerializer serializer )
{
string convertedValue = false == value ? "False" : "True";
writer.WriteValue( convertedValue );
}
public override bool ReadJson( JsonReader reader, Type objectType, bool existingValue, bool hasExistingValue, JsonSerializer serializer )
{
Console.WriteLine( reader.Value.GetType( ).ToString( ) );
// System.String
string value = ( string ) reader.Value;
bool convertedValue = "False" == value ? false : true;
return convertedValue;
}
}
JSON.Net не обслуживает меня уже преобразованный объект bool
.
Это баг или фича?
Это известное поведение Json.Net. Поскольку JSON не имеет встроенного синтаксиса для обозначения дат (как это имеет место для логических значений), они должны быть представлены в виде строк. По умолчанию Json.Net пытается быть красивым и анализирует строки, похожие на даты.
Если вы используете свой собственный конвертер для дат или иным образом хотите обрабатывать данные самостоятельно, вам нужно обязательно установить для параметра DateParseHandling
значение None
в JsonSerializerSettings
, иначе внутренний читатель попытается обработать его первым.
JsonSerializerSettings settings = new JsonSerializerSettings
{
Converters = new List<JsonConverter> { new DateTimeStringConverter() },
DateParseHandling = DateParseHandling.None
};
var foo = JsonConvert.DeserializeObject<Foo>(json, settings);
DateParseHandling
будет по-прежнему применяться ко всем конвертерам независимо от того, помещаете ли вы конвертеры в список в настройках или используете ли вы атрибуты [JsonConverter]
в ваших классах. Я просто собрал их здесь, чтобы показать типичный пример использования.
DateParseHandling
значениеNone
вJsonSerializerSettings
, в противном случае внутреннее устройство чтения сначала попытается обработать его.