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 的完全替代品。它专为速度而构建,考虑了最少的分配,而不是功能完整性。如果你想要验证,你可以
- 使用 Json.NET
- 使用验证程序类序列化后验证对象
- 创建自定义转换器
将军展示了如何做#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);