Json.net 将LocalDate从版本1反序列化为版本2
不幸的是,当我们开始这个项目时,我们没有将配置添加到布线中 这意味着我们在NEventStore中有这样的JSON文档 注意。简化视图。实际上不是事件表示Json.net 将LocalDate从版本1反序列化为版本2,json.net,nodatime,Json.net,Nodatime,不幸的是,当我们开始这个项目时,我们没有将配置添加到布线中 这意味着我们在NEventStore中有这样的JSON文档 注意。简化视图。实际上不是事件表示 dates.json { "$type": "NodatimeIssueTest.Product, NodatimeIssueTest", "FirstDate": { "$type": "NodaTime.LocalDate, NodaTime", "ticks": 1230422400000
dates.json
{
"$type": "NodatimeIssueTest.Product, NodatimeIssueTest",
"FirstDate": {
"$type": "NodaTime.LocalDate, NodaTime",
"ticks": 12304224000000000,
"calendar": "ISO"
},
"SecondDate": {
"$type": "System.Nullable`1[[NodaTime.LocalDate, NodaTime]], mscorlib",
"ticks": 12304224000000000,
"calendar": "ISO"
},
"OtherDates": [
{
"$type": "NodaTime.LocalDate, NodaTime",
"ticks": 12304224000000000,
"calendar": "ISO"
}
],
"FirstDateTime": {
"$type": "NodaTime.LocalDateTime, NodaTime",
"ticks": 12304734100000000,
"calendar": "ISO"
},
"FirstInstant": {
"$type": "NodaTime.Instant, NodaTime",
"ticks": 12304734100000000
}
}
而不是这个
{
"$type": "NodatimeIssueTest.Product, NodatimeIssueTest",
"FirstDate": "2008-12-28",
"SecondDate": "2008-12-28",
"OtherDates": [
"2008-12-28"
],
"FirstDateTime": "2008-12-28T14:10:10",
"FirstInstant": "2008-12-28T14:10:10Z"
}
因此,我们很难升级到最新的NodaTime包,因为我们无法再反序列化json文档
一种解决方案是读取所有NEventStore提交,并使用正确的节点时间解析器进行序列化。但如果这可以避免,我会很高兴
另一种选择是进行自定义转换和数据绑定
但这需要低水平的节点时间逻辑。尽管我们不需要涵盖所有日历,例如。带有自定义转换器和日期活页夹的解决方案
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using NodaTime;
using NodaTime.Serialization.JsonNet;
using NUnit.Framework;
namespace NodatimeIssueTest
{
[TestFixture]
public class TestClass
{
[Test]
public void Deserialize()
{
var serializer = new JsonSerializer();
serializer.NullValueHandling = NullValueHandling.Ignore;
serializer.TypeNameHandling = TypeNameHandling.Objects;
//Custom converters and binder
serializer.Converters.Add(new NodaLocalDateConverter());
serializer.Converters.Add(new NodaLocalDateTimeConverter());
serializer.Converters.Add(new NodaInstantConverter());
serializer.SerializationBinder = new CustomBinder();
using (var sr = new StreamReader($@"{TestContext.CurrentContext.TestDirectory}\dates.json"))
using (var reader = new JsonTextReader(sr))
{
var product = serializer.Deserialize<Product>(reader);
Assert.AreEqual(new LocalDate(2008, 12, 28), product.FirstDate);
Assert.AreEqual(new LocalDate(2008, 12, 28), product.SecondDate);
Assert.AreEqual(new LocalDate(2008, 12, 28), product.OtherDates[0]);
Assert.AreEqual(new LocalDateTime(2008, 12, 28, 14, 10, 10), product.FirstDateTime);
Assert.AreEqual(Instant.FromUtc(2008, 12, 28, 14, 10, 10), product.FirstInstant);
}
}
}
public class Product
{
public LocalDate FirstDate { get; set; }
public LocalDate? SecondDate { get; set; }
public List<LocalDate> OtherDates { get; set; }
public LocalDateTime FirstDateTime { get; set; }
public Instant FirstInstant { get; set; }
}
public class NodaLocalDateConverter : JsonConverter
{
public override bool CanWrite => false;
public override bool CanRead => true;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null) return null;
if (reader.TokenType == JsonToken.StartObject)
{
var custom = (CustomLocalDate) serializer.Deserialize(reader, typeof(CustomLocalDate));
var dateTime = new DateTime(custom.Ticks, DateTimeKind.Utc).AddTicks(new DateTime(1970, 1, 1).Ticks);
var local = LocalDate.FromDateTime(dateTime, CalendarSystem.Iso);
return local;
}
return null;
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(LocalDate) || objectType == typeof(LocalDate?);
}
}
public class NodaLocalDateTimeConverter : JsonConverter
{
public override bool CanWrite => false;
public override bool CanRead => true;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null) return null;
if (reader.TokenType == JsonToken.StartObject)
{
var custom = (CustomLocalDateTime) serializer.Deserialize(reader, typeof(CustomLocalDateTime));
var dateTime = new DateTime(custom.Ticks, DateTimeKind.Utc).AddTicks(new DateTime(1970, 1, 1).Ticks);
var local = LocalDateTime.FromDateTime(dateTime, CalendarSystem.Iso);
return local;
}
return null;
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(LocalDateTime) || objectType == typeof(LocalDateTime?);
}
}
public class NodaInstantConverter : JsonConverter
{
public override bool CanWrite => false;
public override bool CanRead => true;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null) return null;
if (reader.TokenType == JsonToken.StartObject)
{
var custom = (CustomInstant) serializer.Deserialize(reader, typeof(CustomInstant));
var dateTime = new DateTime(custom.Ticks, DateTimeKind.Utc).AddTicks(new DateTime(1970, 1, 1).Ticks);
var local = Instant.FromDateTimeUtc(dateTime);
return local;
}
return null;
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Instant) || objectType == typeof(Instant?);
}
}
public class CustomBinder : DefaultSerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
switch (typeName)
{
case "NodaTime.LocalDate": return typeof(CustomLocalDate);
case "System.Nullable`1[[NodaTime.LocalDate, NodaTime]]": return typeof(CustomLocalDate);
case "NodaTime.LocalDateTime": return typeof(CustomLocalDateTime);
case "System.Nullable`1[[NodaTime.LocalDateTime, NodaTime]]": return typeof(CustomLocalDateTime);
case "NodaTime.Instant": return typeof(CustomInstant);
case "System.Nullable`1[[NodaTime.Instant, NodaTime]]": return typeof(CustomInstant);
default: return base.BindToType(assemblyName, typeName);
}
}
}
public class CustomLocalDate
{
[JsonProperty("ticks")] public long Ticks { get; set; }
[JsonProperty("calendar")] public string Calendar { get; set; }
}
public class CustomLocalDateTime
{
[JsonProperty("ticks")] public long Ticks { get; set; }
[JsonProperty("calendar")] public string Calendar { get; set; }
}
public class CustomInstant
{
[JsonProperty("ticks")] public long Ticks { get; set; }
}
}
使用系统;
使用System.Collections.Generic;
使用System.IO;
使用Newtonsoft.Json;
使用Newtonsoft.Json.Serialization;
使用NodaTime;
使用NodaTime.Serialization.JsonNet;
使用NUnit.Framework;
命名空间节点测试
{
[测试夹具]
公共类TestClass
{
[测试]
public void反序列化()
{
var serializer=new JsonSerializer();
serializer.NullValueHandling=NullValueHandling.Ignore;
serializer.TypeNameHandling=TypeNameHandling.Objects;
//定制转换器和活页夹
serializer.Converters.Add(新的NodaLocalDateConverter());
serializer.Converters.Add(新的NodaLocalDateTimeConverter());
serializer.Converters.Add(new NodaInstantConverter());
serializer.SerializationBinder=新的CustomBinder();
使用(var sr=newstreamreader($@“{TestContext.CurrentContext.TestDirectory}\dates.json”))
使用(var reader=newjsontextreader(sr))
{
var product=serializer.Deserialize(读取器);
AreEqual(新的LocalDate(2008,12,28),product.FirstDate);
AreEqual(新的LocalDate(2008,12,28),product.SecondDate);
Assert.AreEqual(新的LocalDate(2008,12,28),product.OtherDates[0]);
AreEqual(新的LocalDateTime(2008,12,28,14,10,10),product.FirstDateTime);
Assert.AreEqual(Instant.FromUtc(2008,12,28,14,10,10),product.FirstInstant);
}
}
}
公共类产品
{
public LocalDate FirstDate{get;set;}
public LocalDate?SecondDate{get;set;}
公共列表其他日期{get;set;}
public LocalDateTime FirstDateTime{get;set;}
公共即时FirstInstant{get;set;}
}
公共类NodeLocalDateConverter:JsonConverter
{
公共覆盖boolcanwrite=>false;
public override bool CanRead=>true;
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
抛出新的NotImplementedException();
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
if(reader.TokenType==JsonToken.Null)返回Null;
if(reader.TokenType==JsonToken.StartObject)
{
var custom=(CustomLocalDate)序列化程序。反序列化(读取器,typeof(CustomLocalDate));
var dateTime=new dateTime(custom.Ticks,DateTimeKind.Utc).AddTicks(new dateTime(1970,1,1).Ticks);
var local=LocalDate.FromDateTime(dateTime,CalendarSystem.Iso);
返回本地;
}
返回null;
}
公共覆盖布尔CanConvert(类型objectType)
{
返回objectType==typeof(LocalDate)| objectType==typeof(LocalDate?);
}
}
公共类NodaLocalDateTimeConverter:JsonConverter
{
公共覆盖boolcanwrite=>false;
public override bool CanRead=>true;
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
抛出新的NotImplementedException();
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
if(reader.TokenType==JsonToken.Null)返回Null;
if(reader.TokenType==JsonToken.StartObject)
{
var custom=(CustomLocalDateTime)序列化程序。反序列化(读取器,typeof(CustomLocalDateTime));
var dateTime=new dateTime(custom.Ticks,DateTimeKind.Utc).AddTicks(new dateTime(1970,1,1).Ticks);
var local=LocalDateTime.FromDateTime(dateTime,CalendarSystem.Iso);
返回本地;
}
返回null;
}
公共覆盖布尔CanConvert(类型objectType)
{
返回objectType==typeof(LocalDateTime)| | objectType==typeof(LocalDateTime?);
}
}
公共类NodeInstantConverter:JsonConverter
{
公共覆盖boolcanwrite=>false;
public override bool CanRead=>true;
公共重写void WriteJson(JsonWriter编写器、对象值、JsonSerializer序列化器)
{
抛出新的NotImplementedException();
}
公共重写对象ReadJson(JsonReader阅读器,类型objectType,对象existingValue,JsonSerializer序列化程序)
{
if(reader.TokenType==JsonToken.Null)返回Null;
if(reader.TokenType==JsonToken.StartObject)
{
var custom=(CustomInstant)序列化程序。反序列化(reader,typeof(CustomInstant));
var dateTime=new dateTime(custom.Ticks,DateTimeKind.Utc).AddTicks(new dateTime(1970,1,1).Ticks);
var local=Instant.FromDateTimeUtc(日期时间);
返回本地;