Я хочу сериализовать и десериализовать Nullable DateTime to/from JSON, но я не хочу комментировать его JsonConverterAttribute. Тем не менее, я хотел бы сохранить его сразу в JsonSerializerSettings, не раздувая DTO с этими атрибутами, сохраняя DTOs как обычно.Дата не может быть сериализована или десериализована
Вот DTO:
public class Post
{
public DateTime? Created { get; set; }
}
Вот Custom JsonConverter:
internal class EpochDateTimeConverter : Newtonsoft.Json.JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(DateTime).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var t = (long)Convert.ToDouble(reader.Value.ToString());
return t.FromUnixTime();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
long ticks;
DateTime valueAsDate = (DateTime)value;
if (valueAsDate != DateTime.MinValue)
{
if (value is DateTime)
{
var epoc = new DateTime(1970, 1, 1);
var delta = (valueAsDate) - epoc;
if (delta.TotalSeconds < 0)
{
throw new ArgumentOutOfRangeException("Unix epoc starts January 1st, 1970");
}
ticks = (long)delta.TotalSeconds;
}
else
{
throw new Exception("Expected date object value.");
}
writer.WriteValue(ticks);
}
}
}
Вот минимальный репродукция:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
namespace NameSpaceSample
{
public class Post
{
public DateTime? Created { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
var settings = new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore,
Converters = new List<JsonConverter>
{
new EpochDateTimeConverter()
}
};
string postAsJson = JsonConvert.SerializeObject(new Post { Created = DateTime.UtcNow }, settings);
Console.WriteLine(postAsJson);// {"Created":"2015-09-17T17:15:06.6160689Z"}
var json = "{\"Created\":1442510191}";
Post post = JsonConvert.DeserializeObject<Post>(json, settings);//Exception here
Console.ReadKey();
}
}
}
Исключения брошено в этой линии:
JsonReaderException:
Error reading date. Unexpected token: Integer. Path 'Created', line 1, position 21.
Примечание:
Я знаю, что это может быть решено только аннотирования его с JsonConverterAttribute, как показано ниже, но я не хочу, чтобы сделать это для вышеупомянутого причина.
public class Post
{
[JsonConverter(typeof(EpochDateTimeConverter))]
public DateTime? Created { get; set; }
}
Обратите внимание, что эпоха Unix в терминах UTC, но данный 'DateTime' может быть с точки зрения местных, МСВ, или какой-либо другой неопределенный часовой пояс (см. 'DateTimeKind'). Если вы не уверены, что все ваши значения «DateTime» соответствуют UTC, я бы не использовал этот подход. Лучшей практикой для дат в JSON является использование ISO8601, который уже предоставлен JSON.net. –
@MattJohnson Мне это известно. Спасибо, в любом случае :) –