反序列化ASP.NET转换为JSON的DateTime时出错

qni6mghb  于 2023-05-30  发布在  .NET
关注(0)|答案(1)|浏览(228)

我们有一个MAUI应用程序(尽管我不认为这实际上是相关的),它将数据发送到ASP.NET Core最小API。
我们使用一个通用的DTO(简化)...

public record MyDto(DateTime Date);

该应用程序将其序列化如下(再次简化)...

string json = JsonSerializer.Serialize(new MyDto(DateTime.Now));

...并将其发送到API。
API有一些中间件,可以抓取传入的JSON并将其反序列化。

MyDto dto = JsonHelpers.Deserialise<MyDto>(httpContext.Request.Query["data"].ToString());

但是,由于日期的格式,这会引发异常“* 无法转换JSON值 *”。该应用程序正在发送包含格式为2023-05-24T20:20:46.9351772 01:00的日期的JSON,这会导致反序列化器阻塞。
根据这里的许多答案,我尝试了一个自定义JSON转换器,但无法让它工作。例如,我试过...

public class CustomDateTimeConverter : JsonConverter<DateTime?> {
  const string Format = "yyyy-MM-dd hh:mm:ss.fffffff zzz";

  public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
    DateTime.Parse(reader.GetString(), CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);

  public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) =>
    writer.WriteStringValue(value?.ToUniversalTime().ToString(Format, CultureInfo.InvariantCulture));
}

但这仍然是例外。如果我在手动编写的JSON片段上使用此代码,其中日期格式为2023-05-24T20:20:46.9351772,则反序列化器工作正常,因此似乎偏移量是问题所在。我不知道如何设置Format字符串来使用偏移量。
根据this pagezzz应该可以很好地用于偏移量,并且在日期上使用ToString()时确实可以很好地工作。
让我困惑的是,我们在代码中有大量的DTO,包括DateTime属性,并且在API端点中成功地反序列化。我不明白为什么这次会有什么不同。
更让我困惑的是,所有这些都应该由框架来处理。JsonSerializer.Deserialize应该能够处理JsonSerializer.Serialize的输出吧?
有谁能给点建议吗?谢谢

bvn4nwqk

bvn4nwqk1#

代码中有几个问题。
1.反序列化时未使用该格式,因此请使用它。例如:

public class CustomDateTimeConverter : JsonConverter<DateTime?> {
    const string Format = "yyyy-MM-dd HH:mm:ss.fffffff zzz";

    public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
        DateTime.ParseExact(reader.GetString(), Format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal);

    public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) =>
        writer.WriteStringValue(value?.ToString(Format, CultureInfo.InvariantCulture));
}
public record MyDto([property: JsonConverter(typeof(CustomDateTimeConverter))]DateTime? Date);
var myDto = new MyDto(DateTime.Now);
var ser = JsonSerializer.Serialize(myDto);
var deserialize = JsonSerializer.Deserialize<MyDto>(ser);
Console.WriteLine(deserialize.Date == myDto.Date); // true

1.您的格式不能正确表示提供的示例字符串。它应该是这样的-yyyy-MM-ddTHH:mm:ss.fffffff zzz(在日期和时间之间添加T,使用HH代替'hh')
1.看起来zzz需要sign(+/-)- docs,因此您可能需要修复输入(例如使用regex replace来修复它):

var myDto = JsonSerializer.Deserialize<MyDto>("""
{
   "Date": "2023-05-24T20:20:46.9351772 +01:00"
}
""");

public class CustomDateTimeConverter : JsonConverter<DateTime> {
    const string Format = "yyyy-MM-ddTHH:mm:ss.fffffff zzz";

    // TODO - check for empty/null strings, use TryParse
    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
        DateTime.ParseExact(reader.GetString(), Format, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);

    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) =>
        throw new JsonException();
}

P.S.
实际上,如果你在原始字符串中将空格改为+/'-'符号,它看起来像是ISO 8601格式的有效日期,应该可以开箱即用:

var myDto = JsonSerializer.Deserialize<MyDto>("""
{
   "Date": "2023-05-24T20:20:46.9351772+01:00"
}
""");

public record MyDto(DateTime? Date);

相关问题