Json.NET需要反序列化的所有属性



在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

我希望它能帮助到别人。

相关内容

  • 没有找到相关文章

最新更新