反序列化 NodaTime LocalDate 时出现异常

Exception when deserializing NodaTime LocalDate

我在反序列化包含 JSON 序列化 LocalDate 对象的 JSON 字符串时看到异常(请参阅此问题的结尾以获取 JSON 片段)。

这就是我反序列化的方式:

var settings = new JsonSerializerSettings();
settings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
var output = JsonConvert.DeserializeObject<MyObject>(json, settings);

我看到这条异常信息:

NodaTime.Utility.InvalidNodaDataException: 'Unexpected token parsing LocalDate. Expected String, got StartObject.'

这是 MyObject class:

class MyObject
{
    public LocalDate Date { get; set; }
    public string AnotherProperty { get; set; }
}

这是我要反序列化的 JSON 片段:

{
    "Date": {
        "Calendar": {
            "Id": "ISO",
            "Name": "ISO",
            "MinYear": -9998,
            "MaxYear": 9999,
            "Eras": [{
                "Name": "BCE"
            }, {
                "Name": "CE"
            }]
        },
        "Year": 2017,
        "Month": 7,
        "Day": 10,
        "DayOfWeek": 1,
        "YearOfEra": 2017,
        "Era": {
            "Name": "CE"
        },
        "DayOfYear": 191
    },
    "AnotherProperty": "A string"
}

我现在想通了 - 我的问题是我在 ASP.NET 路由处理程序中的错误假设。 @L.B 的问题实际上让我多了一些思考。

我假设内置 JSON 序列化器在这个例子中正确地序列化了 MyObject 中的 LocalDate:

[HttpGet("myobject")]
public MyObject GetMyObject()
{
    return new MyObject()
    {
        Date = LocalDate.FromDateTime(DateTime.Now),
        AnotherProperty = "A string"
    };
}

此 API 的结果与问题中的 JSON 片段相同。

为每个 API 处理程序调用 SerializeObject 并传递 settings 也不是一个好主意,因为我在每个路由处理程序上丢失了对象 return 类型我有。

为了确保 LocalDate 每个 处理程序中正确序列化,我在 StartupConfigureServices 方法中执行以下操作 class:

services.AddMvc().AddJsonOptions(options =>
{
    // NodaConverters lives in the NodaTime.Serialization.JsonNet assembly
    options.SerializerSettings.Converters.Add(NodaConverters.LocalDateConverter);
});

现在当我调用上面的 API 时,LocalDate 被正确序列化,像这样:

{
    "Date":"2017-07-10",
    "AnotherProperty":"A string"
}

这是 DeserializeObject 也期望的格式。

你可以使用这样的class结构

public class Era
{
    public string Name { get; set; }
}

public class Calendar
{
    public string Id { get; set; }
    public string Name { get; set; }
    public int MinYear { get; set; }
    public int MaxYear { get; set; }
    public List<Era> Eras { get; set; }
}

public class Era2
{
    public string Name { get; set; }
}

public class Date
{
    public Calendar Calendar { get; set; }
    public int Year { get; set; }
    public int Month { get; set; }
    public int Day { get; set; }
    public int DayOfWeek { get; set; }
    public int YearOfEra { get; set; }
    public Era2 Era { get; set; }
    public int DayOfYear { get; set; }
}

public class RootObject
{
    public Date Date { get; set; }
    public string AnotherProperty { get; set; }
}