在Json.NET中,如何使所有属性在反序列化时都是必需的?我知道我可以用消息上的属性来做这件事,但我不想那样做。主要是因为它需要我的消息库承担外部依赖关系。
我尝试了MissingMemberHandling.Error设置,但它的作用与我想要的相反。我同意JSON有额外的属性。当JSON中缺少任何目标对象属性时,我希望它失败。
实际上,我正在反序列化为F#记录,而且这些属性通常都不能为null。(在代码中,不能通过正常方式将它们赋值为null。)但是,当数据丢失时,Json.NET很乐意将属性默认为null。
F#版本的已接受答案
解析程序
open System
open Newtonsoft.Json
open Newtonsoft.Json.Serialization
type RequireAllPropertiesContractResolver() =
inherit DefaultContractResolver()
override me.CreateObjectContract(objectType:Type) =
let contract = base.CreateObjectContract(objectType)
contract.ItemRequired <- new Nullable<Required>(Required.Always)
contract
在设置中
let settings = new JsonSerializerSettings() // default settings
...
settings.ContractResolver <- new RequireAllPropertiesContractResolver()
如果您的模型具有JSON可能忽略的属性,并且您希望这是一个错误,请将属性[JsonObject(ItemRequired=Required.Always)]
添加到类中:
类型:必需
一个值,指示是否需要对象的属性。
Required
的可能值为:
- 默认值:该属性不是必需的。默认状态
- AllowNull:属性必须在JSON中定义,但不能为null值
- Always:属性必须在JSON中定义,并且不能为null值
- 不允许null:该属性不是必需的,但它不能是null值[如果存在]。(Json.NET 8.0.1及更高版本。)
该设置是继承的,因此可以添加到泛型基类中。
更新
要对所有对象全局执行此操作,请将DefaultContractResolver
子类化,并将ItemRequired
标志添加到所有对象契约中:
public class RequireObjectPropertiesContractResolver : DefaultContractResolver
{
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
contract.ItemRequired = Required.Always;
return contract;
}
}
然后,在设置中:
var settings = new JsonSerializerSettings { ContractResolver = new RequireObjectPropertiesContractResolver() };
注:
如果您的f#成员是
optional
时不想要求JSON属性,请参阅此问题的答案,以及JSON.NET根据属性类型使属性成为必需属性的问题。此协定冲突解决程序将默认设置
Required.Always
应用于所有对象属性,但在直接应用时不会覆盖JsonProperty.AttributeRequired
。如果您需要,请参阅例如如何覆盖";必需。总是";在newtonsoft json中。如问题中所述,设置
MissingMemberHandling = MissingMemberHandling.Error
解决了一个补充问题:如果JSON可能具有模型忽略的属性,并且您希望这是一个错误,请使用MissingMemberHandling.Error
。请参阅:MissingMemberHandling设置。您可能需要缓存合同冲突解决程序以获得最佳性能。
我知道我在这里聚会迟到了,但是。。。接受的答案强制所有属性都可用,当您的记录包含选项类型并与JsonSerializerSettings
上的NullValueHandling.Ignore
参数组合时,这可能不太好。在这种情况下,您将要求选项类型存在,这太有限了。我们发现这个解决方案对我们有效:
type RequireAllPropertiesContractResolver() =
inherit CamelCasePropertyNamesContractResolver()
override __.CreateProperty(memb, serialization) =
let prop = base.CreateProperty(memb, serialization)
let isRequired = not (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() = typedefof<option<_>>)
if isRequired then prop.Required <- Required.Always
prop
我希望它能帮助到别人。