在我的 ASP.NET Core Web-API 项目中,我收到了对我的一个 API Controller 的 HTTP POST 调用。
在评估 JSON 负载并反序列化其内容时,Json.NET 偶然发现了 0001-01-01T00:00:00
的 DateTime 值,并且无法将其转换为 DateTimeOffset 属性。
我注意到该值应该代表 DateTimeOffset.MinValue 的值,但它缺少时区似乎会使解串器出错。我只能想象 DateTimeOffset.Parse 会尝试将其转换为主机当前时区,这会导致 DateTimeOffset.MinValue 下溢。
这个属性非常简单:
[JsonProperty("revisedDate", NullValueHandling = NullValueHandling.Ignore)]
public DateTimeOffset? RevisedDate { get; set; }
这是发送给客户端的响应:
{
"resource.revisedDate": [
"Could not convert string to DateTimeOffset: 0001-01-01T00:00:00. Path 'resource.revisedDate', line 20, position 44."
]
}
我正在使用 Newtonsoft.Json v11.0.2,目前处于 UTC + 2(德国)。异常回溯和错误消息在这里:https://pastebin.com/gX9R9wq0 .
我无法修复调用代码,所以我必须在我这边修复它。
但问题是:怎么做?
最佳答案
问题 似乎只有在机器的时区 TimeZoneInfo.Local
时才能重现与 UTC 有正偏移,例如(UTC+01:00) 阿姆斯特丹、柏林、伯尔尼、罗马、斯德哥尔摩、维也纳
。我无法在具有非正偏移量的时区重现它,例如 UTC-05:00
或 UTC 本身。
具体来说,在 JsonReader.ReadDateTimeOffsetString()
使用 DateTimeStyles.RoundtripKind
调用 DateTimeOffset.TryParse
:
if (DateTimeOffset.TryParse(s, Culture, DateTimeStyles.RoundtripKind, out dt))
{
SetToken(JsonToken.Date, dt, false);
return dt;
}
这显然会导致具有正 UTC 偏移量的时区出现下溢错误。如果在调试器中我使用 DateTimeStyles.AssumeUniversal
进行解析,则可以避免该问题。
您可能想要 report an issue关于这个给 Newtonsoft。只有当计算机的时区具有特定值时,特定 DateTimeOffset
字符串的反序列化才会失败这一事实似乎是错误的。
解决方法是使用 IsoDateTimeConverter
使用 IsoDateTimeConverter.DateTimeStyles
反序列化您的 DateTimeOffset
属性设置为 DateTimeStyles.AssumeUniversal
。此外,有必要通过设置 JsonReader.DateParseHandling = DateParseHandling.None
来禁用 JsonReader
内置的自动 DateTime
识别功能。 ,这必须在阅读器开始解析您的 DateTimeOffset
属性的值之前完成。
首先,定义如下JsonConverter
:
public class FixedIsoDateTimeOffsetConverter : IsoDateTimeConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(DateTimeOffset) || objectType == typeof(DateTimeOffset?);
}
public FixedIsoDateTimeOffsetConverter() : base()
{
this.DateTimeStyles = DateTimeStyles.AssumeUniversal;
}
}
现在,如果您可以修改 Controller 的 JsonSerializerSettings
,请使用以下设置:
var settings = new JsonSerializerSettings
{
DateParseHandling = DateParseHandling.None,
Converters = { new FixedIsoDateTimeOffsetConverter() },
};
如果您不能轻松修改 Controller 的JsonSerializerSettings
,则需要从this answer 获取DateParseHandlingConverter
给 How to prevent a single object property from being converted to a DateTime when it is a string 并将其与 FixedIsoDateTimeOffsetConverter
一起应用于您的模型,如下所示:
[JsonConverter(typeof(DateParseHandlingConverter), DateParseHandling.None)]
public class RootObject
{
[JsonProperty("revisedDate", NullValueHandling = NullValueHandling.Ignore)]
[JsonConverter(typeof(FixedIsoDateTimeOffsetConverter))]
public DateTimeOffset? RevisedDate { get; set; }
}
DateParseHandlingConverter
必须应用于模型本身而不是 RevisedDate
属性,因为 JsonReader
已经识别出 0001-01 -01T00:00:00
作为调用 FixedIsoDateTimeOffsetConverter.ReadJson()
之前的 DateTime
。
更新
在comments , @RenéSchindhelm写道,我创建了一个问题让 Newtonsoft 知道。它是 Deserialization of DateTimeOffset value fails depending on system's timezone #1731 .
关于c# - 对于没有时区的 DateTimeOffset.MinValue,Json.NET 反序列化 DateTimeOffset 值失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50628374/