我们将Asp.NET应用程序从.Net Framework 4.7.2更新为.Net 5。现在,我们在控制器方法中遇到了反序列化JSON的问题。在旧版本中,我们使用Newtonsoft.JSON。以前,如果我们在JSON中为不可空类型(如int)的属性获取空值,反序列化器将采用默认值。或忽略了null和错误,并且没有覆盖对象创建时属性的默认值。但是现在,在出现错误后,整个对象都被设置为null。
第一个
预期与之前类似将是Cwe = false且所有HoursXXInHours = 0的OrderEffortDto示例
我们得到的结果是OrderEffortDto = null
我们已经尝试在新版本中使用Newtonsoft,但结果相同。我们还配置了SerializerSettings.NullValueHandling = NullValueHandling.Ignore
。这对该问题有效,但对于另一个方向,对于DTO到JSON的序列化,空值也会被忽略,其中需要空值。
有没有办法恢复原来的行为?是的,在前端修复这个问题,将正确的值放入JSON中是没有问题的,但是我们的应用程序很大,要确定所有需要纠正的地方,这很容易出错。
Update 1适用于可能遇到相同问题的用户
我创建了两个简单的测试项目,一个是使用.Net Framework 4.7.2的ASP.NET WebApi,另一个是使用.Net 5的ASP.NET WebApi,使用上面的JSON和DTO示例。我从Newtonsoft获得了两个类似的跟踪错误,并且已经描述了控制器中DTO的结果。另外,.Net 5中的System.Text.Json为整个DTO提供了一个空值。
- 适用于带有.Net Framework 4.7.2的API *
2022-03-24T10:50:05.368 Info Started deserializing WebApplication1NetFramework.Data.OrderEffortDto. Path 'effortType', line 2, position 16.
2022-03-24T10:50:05.388 Error Error deserializing WebApplication1NetFramework.Data.OrderEffortDto. Error converting value {null} to type 'System.Boolean'. Path 'cwe', line 3, position 14.
2022-03-24T10:50:05.403 Error Error deserializing WebApplication1NetFramework.Data.OrderEffortDto. Error converting value {null} to type 'System.Decimal'. Path 'hours25InHours', line 7, position 25.
2022-03-24T10:50:05.403 Error Error deserializing WebApplication1NetFramework.Data.OrderEffortDto. Error converting value {null} to type 'System.Decimal'. Path 'hours50InHours', line 8, position 25.
2022-03-24T10:50:05.403 Error Error deserializing WebApplication1NetFramework.Data.OrderEffortDto. Error converting value {null} to type 'System.Decimal'. Path 'hours100InHours', line 9, position 26.
2022-03-24T10:50:05.404 Error Error deserializing WebApplication1NetFramework.Data.OrderEffortDto. Error converting value {null} to type 'System.Decimal'. Path 'hours150InHours', line 10, position 26.
2022-03-24T10:50:05.404 Verbose Could not find member 'orderNumber' on WebApplication1NetFramework.Data.OrderEffortDto. Path 'orderNumber', line 11, position 17.
2022-03-24T10:50:05.405 Verbose Could not find member 'withCosts' on WebApplication1NetFramework.Data.OrderEffortDto. Path 'withCosts', line 12, position 15.
2022-03-24T10:50:05.407 Info Finished deserializing WebApplication1NetFramework.Data.OrderEffortDto. Path '', line 16, position 1.
2022-03-24T10:50:05.407 Verbose Deserialized JSON:
{
"effortType": "1",
"cwe": null,
"distanceInKilometers": null,
"effortDate": "2022-03-22T14:45:00+01:00",
"effortInHours": 1.0,
"hours25InHours": null,
"hours50InHours": null,
"hours100InHours": null,
"hours150InHours": null,
"orderNumber": "006001780872",
"withCosts": false,
"isNew": true,
"isEdited": false,
"isDeleted": false
}
- 适用于.Net 5的API *
2022-03-24T10:48:19.162 Info Started deserializing WebApplication1NetCore.Data.OrderEffortDto. Path 'effortType', line 2, position 16.
2022-03-24T10:48:19.180 Error Error deserializing WebApplication1NetCore.Data.OrderEffortDto. Error converting value {null} to type 'System.Boolean'. Path 'cwe', line 3, position 14.
2022-03-24T10:48:19.196 Error Error deserializing WebApplication1NetCore.Data.OrderEffortDto. Error converting value {null} to type 'System.Decimal'. Path 'hours25InHours', line 7, position 25.
2022-03-24T10:48:19.196 Error Error deserializing WebApplication1NetCore.Data.OrderEffortDto. Error converting value {null} to type 'System.Decimal'. Path 'hours50InHours', line 8, position 25.
2022-03-24T10:48:19.197 Error Error deserializing WebApplication1NetCore.Data.OrderEffortDto. Error converting value {null} to type 'System.Decimal'. Path 'hours100InHours', line 9, position 26.
2022-03-24T10:48:19.197 Error Error deserializing WebApplication1NetCore.Data.OrderEffortDto. Error converting value {null} to type 'System.Decimal'. Path 'hours150InHours', line 10, position 26.
2022-03-24T10:48:19.197 Verbose Could not find member 'orderNumber' on WebApplication1NetCore.Data.OrderEffortDto. Path 'orderNumber', line 11, position 17.
2022-03-24T10:48:19.197 Verbose Could not find member 'withCosts' on WebApplication1NetCore.Data.OrderEffortDto. Path 'withCosts', line 12, position 15.
2022-03-24T10:48:19.199 Info Finished deserializing WebApplication1NetCore.Data.OrderEffortDto. Path '', line 16, position 1.
2022-03-24T10:48:19.200 Verbose Deserialized JSON:
{
"effortType": "1",
"cwe": null,
"distanceInKilometers": null,
"effortDate": "2022-03-22T14:45:00+01:00",
"effortInHours": 1.0,
"hours25InHours": null,
"hours50InHours": null,
"hours100InHours": null,
"hours150InHours": null,
"orderNumber": "006001780872",
"withCosts": false,
"isNew": true,
"isEdited": false,
"isDeleted": false
}
感谢@dbc的评论。我将尝试与转换器在提到的职位Json.net deserialization null guid case,但也将记录发生,以修复根本原因。
更新2
我对转换器做了一些修改,使用了“SwaggerGen.TypeExtensions.GetDefaultValue()",这样我就可以删除泛型,对所有不可为空的类型使用一个转换器。
public class NullToDefaultConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
var defaultValue = objectType.GetDefaultValue();
return defaultValue != null;
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var token = JToken.Load(reader);
if (token.Type == JTokenType.Null)
// here I will add a logger to get all faulty calls
return objectType.GetDefaultValue();
return token.ToObject(objectType); // Deserialize using default serializer
}
// Return false I don't want default values to be written as null
public override bool CanWrite => false;
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
2条答案
按热度按时间jaxagkaj1#
这是一个很好的问题,我最近在将一个大型(错误缠身的)遗留代码库从.NET Framework迁移到.NET Core时也遇到了这个问题。
OP的更新非常有帮助,但是我想分享一个稍微简化的、性能更高的解决方案,它消除了对
SwaggerGen.TypeExtensions.GetDefaultValue()
的依赖,也没有泛型依赖;因此可以将其作为Converter全局应用:当Json .NET反序列化时,通过
object existingValue
输入参数提供当前现有值或默认值,该参数将具有属性的默认值或属性初始值设定项设置的初始值。在这两种情况下,我们可能都希望保留该值,因此可以只返回它,从而提供与旧的.NET Framework Web API行为更兼容的行为(如观察员的帖子所述)。还要注意,我们只需要处理那些 * 不能被分配 *
null
值的属性,因此可以在Type上进行更高性能的检查(改编自优雅的stack overflow answer here)。为了进一步扩展如何在全局范围内恢复遗留兼容行为,我们实现了一个自定义的Input Formatter,如下所示:
通过以下方式配置为供所有模型绑定使用:
EDIT -优化版本现已在Nuget上共享:
自从最初分享这个解决方案以来,我意识到有一些性能影响和一些其他的兼容性问题,比如错误处理,需要解决。实作自订
JsonBufferedHttpRequestReader
和CharArrayPool
,而非以不必要的配置序列化至字串。它还通过将所有错误推入ModelState
并防止抛出这些异常来实现错误处理的传统兼容性。此完整版本可在Nuget上获得,网址为:https://github.com/cajuncoding/AspNetCoreMigrationShims
并且可以像Newtonsoft一样通过以下方式轻松配置:
ccrfmcuu2#
仅使属性可为空
也可以添加构造函数而不是使其可为null。只能在构造函数中包含在反序列化过程中需要更改的属性