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

时间:2012-06-15 17:07:25

标签: c# json json.net datacontract datamember

我们在使用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]属性的事实?

注意: 在.NET中使用JavaScriptSerializer可以很好地处理FullName属性,但是DateTimes会被破坏。我需要JSON.NET忽略这个类具有DataContract / DataMember属性的事实,并且只是执行标准的公共字段序列化,就像它们不存在一样。

6 个答案:

答案 0 :(得分:24)

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

[DataContract]
[JsonObject(MemberSerialization.OptOut)]

答案 1 :(得分:17)

正如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()
});

希望这有帮助!

答案 2 :(得分:14)

我遇到了与您所拥有的问题几乎相关的问题,并通过查看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()
});

答案 3 :(得分:7)

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

  

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

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

答案 4 :(得分:7)

如果您想忽略所有类型DataContractAttribute的存在而不必添加其他属性,那么custom contract resolver是正确的解决方案。但是,从Json.NET 9.0.1 Amry's resolver开始不再有效。 Doolali's resolver有效但序列化所有公共属性(包括标有[JsonIgnore]的公共属性)会产生额外的副作用。如果您需要合同解析程序忽略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

答案 5 :(得分:-2)

你试过这个吗?

IgnoreDataMemberAttribute