当属性丢失时,如何强制System.Text.Json序列化程序抛出异常?



Json.NET 行为可以通过属性定义:如果 JSON 有效负载不包含必需属性,则使用默认值或仅引发异常。

然而System.Text.Json序列化程序默默地什么都不做。
上课:

public sealed class Foo
{
[Required]
public int Prop {get;set;} = 10;
}

和反序列化空对象:

JsonSerializer.Deserialize<Foo>("{}");

我只是得到了一个Foo的实例,Prop=10. 我在JsonSerializerOptions中找不到任何设置来强制它引发异常。可能吗?

System.Text.Json 如果未收到目标类型的某个属性的值,则不会引发异常。您需要实现自定义转换器。

参考: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to#required-properties

System.Text.Json 不是 Json.NET 的完全替代品。它专为速度而构建,考虑了最少的分配,而不是功能完整性。如果你想要验证,你可以

  1. 使用 Json.NET
  2. 使用验证程序类序列化后验证对象
  3. 创建自定义转换器

将军展示了如何做#3。自定义验证器必须显式处理所有验证并返回一些有意义的异常。如果只有一个属性要检查,则抛出ArgumentNullException就足够了。验证多个属性需要更复杂的内容(如 ValidationException(来包含验证结果。

K. Scott Allen 的文章 使用数据注释进行手动验证 展示了如何执行 #2。

一种选择是使用 Validator.ValidateObject 来验证对象并获得包含所有失败验证的ValidationException

try
{
var validationCtx=new ValidationContexgt(myFoo);
Validator.ValidateObject(myFoo,validationCtx);
}
catch(ValidatinException ex)
{
//Do something with the results.
}

如果无效对象很少见,这是可以的,因为引发异常的成本很高。也许更好的选择是使用 Validator.TryValidateObject :

var results = new List<ValidationResult>();
var validationCtx=new ValidationContexgt(myFoo);
if(Validator.TryValidateObject(myFoo,validationCtx,results))
{
//Use the object
}
else
{
//Do something with the failed results
}

System.Text.Json中的[JsonRequired]属性按请求工作,但它从 .NET 7 开始可用。请参阅必需的属性文档。

此外,在 .NET 8 中,还可以使用JsonUnmappedMemberHandling.Disallow选项强制 JSON 字符串正确映射到 POCO/model 属性。请参阅在反序列化期间处理缺少的成员文档。

你需要做的是 SetMissingMemberHandling,它会为你处理每件事,但你需要安装 DevBetter.JsonExtensions Missing MemberHandling.Ignore and MissingMemberHandling.Error

var deserializeOptions = new JsonSerializerOptions()
.SetMissingMemberHandling(MissingMemberHandling.Ignore);
var weatherForecast = JsonSerializer.Deserialize<WeatherForecast>(jsonString, deserializeOptions);

传入DefaultJsonTypeInfoResolver的实现,该实现根据需要标记每个属性。

using System.Text.Json;
var options = new JsonSerializerOptions {
TypeInfoResolver = new DefaultJsonTypeInfoResolver {
Modifiers = {
typeInfo => {
foreach (JsonPropertyInfo property in typeInfo.Properties) {
property.IsRequired = true;
}
}
}
}
};
return JsonSerializer.Deserialize<T>(content, options);

相关内容

最新更新