首页 文章

配置JSON.NET以忽略DataContract / DataMember属性

提问于
浏览
32

我们在使用Microsoft JSON序列化程序和JSON.NET的MVC3项目中遇到了这种情况 .

每个人都知道DateTime在Microsoft的序列化程序中基本上被破坏了,所以我们切换到JSON.NET以避免这个问题 . 这很好用,除了我们尝试序列化的一些类是具有DataContract / DataMember属性的POCO . 它们在多个位置引用的程序集中定义 . 此外,它们还具有一些其他显示属性,这些属性未标记为DataMembers以提高效率 . 例如,客户

[DataContract]
public class Customer
{
   [DataMember]
   public string FirstName { get; set;}
   [DataMember]
   public string LastName { get; set;}
   public string FullName 
   {
       get
       {  return FirstName + " " + LastName; }
   }

}

当这个客户通过WCF传递时,客户端可以引用该程序集并使用FullName就好了,但是当使用JSON.NET序列化时,它看到FullName不是 [DataMember] 并且没有序列化它 . 是否有一个选项可以传递给JSON.NET,告诉它忽略一个类应用了 [DataContract] 属性的事实?

Note: 在.NET中使用JavaScriptSerializer适用于FullName属性,但DateTimes已损坏 . 我需要JSON.NET忽略这个类具有DataContract / DataMember属性的事实,并且只是执行标准的公共字段序列化,就像它们不在那里一样 .

6 回答

  • 17

    只需使用Json.Net的OptOut属性即可 . 它将优先于DataContract .

    [DataContract]
    [JsonObject(MemberSerialization.OptOut)]
    
  • 6

    正如Amry所说,你可以使用自己的IContractResolver .

    不幸的是,Amry提供的解决方案对我不起作用,下面是我设法开始工作的解决方案:

    public class AllPropertiesResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            JsonProperty property = base.CreateProperty(member, memberSerialization);
    
            //property.HasMemberAttribute = true;
            property.Ignored = false;
    
            //property.ShouldSerialize = instance =>
            //{
            //    return true;
            //};
    
            return property;
        }
    }
    

    有几行评论,这些不需要让我的解决方案工作,但你永远不知道!

    这与Amry的解决方案具有相同的用法:

    var json = JsonConvert.SerializeObject(result, new JsonSerializerSettings {
        ContractResolver = new AllPropertiesResolver()
    });
    

    希望这可以帮助!

  • -1

    我遇到了与您所拥有的问题几乎相关的问题,并通过浏览Json.NET的代码找到了解决方案 . 所以它可能不是最好的解决方案,但它对我有用 .

    为此,您需要实现自己的 IContractResolver . 过度简化的实现包括所有参数并忽略所有属性(不仅仅是 DataContract ,而是其他内置的Json.NET规则,因此您设置的最初应影响成员选择的任何选项现在都被此代码覆盖):

    class AllPropertiesResolver : DefaultContractResolver
    {
        protected override List<MemberInfo> GetSerializableMembers(Type objectType)
        {
            return objectType.GetProperties()
                .Where(p => p.GetIndexParameters().Length == 0)
                .Cast<MemberInfo>()
                .ToList();
        }
    }
    

    这里是代码用法示例:

    var json = JsonConvert.SerializeObject(result, new JsonSerializerSettings {
        ContractResolver = new AllPropertiesResolver()
    });
    
  • 14

    如果您想忽略所有类型的 DataContractAttribute 的存在而不必添加其他属性,那么custom contract resolver是正确的解决方案 . 但是,从Json.NET 9.0.1开始Amry's resolver不再有效 . Doolali's resolver有效,但它具有序列化所有公共属性的附加副作用,包括标有[JsonIgnore]的属性 . 如果您需要 Contract 解析程序仅忽略 DataContractAttribute 的存在但行为类似于默认合约解析程序,则可以使用以下内容:

    public class IgnoreDataContractContractResolver : DefaultContractResolver
    {
        static MemberSerialization RemoveDataContractAttributeMemberSerialization(Type type, MemberSerialization memberSerialization)
        {
            if (memberSerialization == MemberSerialization.OptIn)
            {
                type = Nullable.GetUnderlyingType(type) ?? type;
    
                // Json.NET interprets DataContractAttribute as inherited despite the fact it is marked with Inherited = false
                // https://json.codeplex.com/discussions/357850
                // https://stackoverflow.com/questions/8555089/datacontract-and-inheritance
                // https://github.com/JamesNK/Newtonsoft.Json/issues/603
                // Thus we need to manually climb the type hierarchy to see if one is present.
    
                var dataContractAttribute = type.BaseTypesAndSelf().Select(t => t.GetCustomAttribute<DataContractAttribute>()).FirstOrDefault(a => a != null);
                var jsonObjectAttribute = type.GetCustomAttribute<JsonObjectAttribute>();
    
                if (dataContractAttribute != null && jsonObjectAttribute == null)
                    memberSerialization = MemberSerialization.OptOut;
            }
            return memberSerialization;
        }
    
        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            var properties = base.CreateProperties(type, RemoveDataContractAttributeMemberSerialization(type, memberSerialization));
            return properties;
        }
    
        protected override JsonObjectContract CreateObjectContract(Type objectType)
        {
            var contract = base.CreateObjectContract(objectType);
            contract.MemberSerialization = RemoveDataContractAttributeMemberSerialization(objectType, contract.MemberSerialization);
            return contract;
        }
    }
    
    public static class TypeExtensions
    {
        public static IEnumerable<Type> BaseTypesAndSelf(this Type type)
        {
            while (type != null)
            {
                yield return type;
                type = type.BaseType;
            }
        }
    }
    

    你可能想要cache the contract resolver for best performance .

  • 7

    根据Json.NET文档,如果属性也使用Json.NET特定属性(例如 [JsonProperty] )进行注释,则忽略 [DataMember] 属性 . 有关详细信息,请参阅Serialization Attributes documentation

    Json.NET属性主要使用标准的.NET序列化属性,例如:如果JsonPropertyAttribute和DataMemberAttribute都存在于属性上并且都自定义名称,则将使用JsonPropertyAttribute中的名称 .

    该文档仅涵盖name属性,但根据我的经验, [JsonProperty] 属性也完全遮蔽 [DataMember] 属性完成的设置 . 因此,如果它适用于您的情况,还要将Json.NET属性添加到应忽略[DataMember]注释的属性 .

  • 20

    你试过这个吗?

    IgnoreDataMemberAttribute

相关问题