如何在Json.NET中将缺少的属性反序列化为默认值?

Gre*_*reg 5 json.net

我有一个用DataContract和DataMember属性注释的类.有些成员被标记为DataMember(IsRequired = true).当我从Json.NET通过线路序列化实例,并且所需的对象成员具有null值时,它们的序列化值在输出中丢失(这显然相当于在JSON中为null).我没关系.

我创建了一种"echo"服务,它返回作为响应发送给它的数据.因此,此服务接收具有缺少成员的JSON(或根据您的查看方式为null成员),然后将其发送回我的Json.NET客户端.通过Fiddler(代理嗅探器)查看,线路上的JSON在两个方向上看起来都是一样的.到现在为止还挺好.

当原始Json.NET发送方收到JSON响应以反序列化它时,序列化程序抛出一个关于在JSON有效负载中找不到所需成员的异常:

Required property 'IAmRequired' not found in JSON. Path ''.
Run Code Online (Sandbox Code Playgroud)

这是不幸的,因为序列化程序因此无法反序列化它之前已经序列化的数据而没有问题.

如果没有更改DataContract类以使成员不需要(由于多种原因我不想这样做),有没有办法让Json.NET将缺少的成员反序列化为默认值,例如null?

这是我的反序列化代码:

HasRequired h = null;
JObject json = response as JObject; // hand waving here
try
{
    JsonSerializer ser = new JsonSerializer();
    ser.MissingMemberHandling = MissingMemberHandling.Ignore; // doesn't seem to help
    ser.DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate; // doesn't seem to help
    ser.NullValueHandling = NullValueHandling.Include; // doesn't seem to help
    h = json.ToObject<HasRequired>(ser);
}
catch (Exception ex)
{
    // bummer, missing required members still
}
Run Code Online (Sandbox Code Playgroud)

Bri*_*ers 5

如果您有标记为 的属性[DataMember(Required = true)]并且想要覆盖所需的行为,您可以执行以下操作:

  1. 您可以用 标记这些相同的属性[JsonProperty(Required = Required.Default)]。这是有效的,因为在 Json.Net 中[JsonProperty]优先[DataMember]。

    [DataContract]
    public class HasRequired
    {
        [DataMember(Required = true)]
        [JsonProperty(Required = Required.Default)]
        public string IAmRequired { get; set; }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 或者,您可以创建一个自定义 ContractResolver,以编程方式设置Required = Required.Default每个属性。

    class CustomResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            JsonProperty prop = base.CreateProperty(member, memberSerialization);
            prop.Required = Required.Default;
            return prop;
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    要使用解析器,只需将ContractResolver序列化器上的属性设置为自定义解析器的新实例:

    JsonSerializer ser = new JsonSerializer();
    ser = new CustomResolver();
    
    Run Code Online (Sandbox Code Playgroud)


Gre*_*reg 0

这看起来像是我的代码上的一个真正的缺陷,并且需要对每个可为空但必需的成员重复,但它有效,并且似乎增加了可以忽略不计的开销。我在原始代码片段中的 try 块之前添加了此内容:

JToken maybeHasIt = null;
if (!json.TryGetValue("IAmRequired", StringComparison.InvariantCultureIgnoreCase, out maybeHasIt))
{
    json.Add("IAmRequired", null);
}
Run Code Online (Sandbox Code Playgroud)