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

如何将缺少的属性反序列化为Json.NET中的默认值?,json.net,Json.net,我有一个用DataContract和DataMember属性注释的类。有些成员被标记为DataMember(IsRequired=true)。当我从Json.NET在线序列化实例时,如果所需的对象成员具有null值,那么它们的序列化值在输出中就会丢失(这显然相当于在Json中为null)。我同意 我创建了一种“echo”服务,它返回发送给它的数据作为响应。因此,该服务接收缺少成员的JSON(或空成员,具体取决于您对它的看法),然后将其发送回我的JSON.NET客户端。通过Fiddler(代理嗅探

我有一个用DataContract和DataMember属性注释的类。有些成员被标记为
DataMember(IsRequired=true)
。当我从Json.NET在线序列化实例时,如果所需的对象成员具有null值,那么它们的序列化值在输出中就会丢失(这显然相当于在Json中为null)。我同意

我创建了一种“echo”服务,它返回发送给它的数据作为响应。因此,该服务接收缺少成员的JSON(或空成员,具体取决于您对它的看法),然后将其发送回我的JSON.NET客户端。通过Fiddler(代理嗅探器)查看,线上的JSON在两个方向上看起来都一样。到目前为止还不错

当原始Json.NET发送方收到Json响应以对其进行反序列化时,序列化程序会抛出一个异常,该异常与在Json负载中找不到所需成员有关:

Required property 'IAmRequired' not found in JSON. Path ''.
这是不幸的,因为序列化程序因此无法对以前序列化的数据进行反序列化,而不会出现问题

除了更改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
}
HasRequired h=null;
JObject json=响应为JObject;//在这里挥手
尝试
{
JsonSerializer ser=新的JsonSerializer();
ser.MissingMemberHandling=MissingMemberHandling.Ignore;//似乎没有帮助
ser.DefaultValueHandling=DefaultValueHandling.IgnoreAndPopulate;//似乎没有帮助
ser.NullValueHandling=NullValueHandling.Include;//似乎没有帮助
h=json.ToObject(ser);
}
捕获(例外情况除外)
{
//糟糕,仍然缺少必需的成员
}

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

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

如果您有标记为
[DataMember(Required=true)]
的属性,并且您希望覆盖所需的行为,那么您可以做以下几件事:

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

    [DataContract]
    public class HasRequired
    {
        [DataMember(Required = true)]
        [JsonProperty(Required = Required.Default)]
        public string IAmRequired { get; set; }
    }
    
  • 或者,您可以创建一个自定义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;
        }
    }
    
    要使用冲突解决程序,只需将序列化程序上的
    ContractResolver
    属性设置为自定义冲突解决程序的新实例:

    JsonSerializer ser = new JsonSerializer();
    ser = new CustomResolver();
    

  • 等等,您已经将成员标记为必需,但它们确实不是必需的?它们是必需的。。。但是仅仅为了满足DataContractSerializer能够处理WCF的序列化(对于SOAP绑定)的一些迟钝规则,并且不会让类型在客户端看来很糟糕。我知道你在说什么;如果不是DC序列化程序,它们将是可选的。对于我试图避免提及的SOAP序列化端,对象被序列化为XML null实例(它们被显式地作为null发送)。我添加了一个答案,应该对您有所帮助。