42

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

每个人都知道微软的序列化器中的 DateTime 基本上被破坏了,所以我们切换到 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 不是 a[DataMember]并且不会序列化它。是否有一个选项可以传递给 JSON.NET 来告诉它忽略一个类已应用属性的事实[DataContract]

注意: 在 .NET 中使用 JavaScriptSerializer 对 FullName 属性效果很好,但 DateTimes 被破坏了。我需要 JSON.NET 来忽略此类具有 DataContract/DataMember 属性的事实,并且只执行标准的公共字段序列化,就像它们不存在时一样。

4

6 回答 6

37

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

[DataContract]
[JsonObject(MemberSerialization.OptOut)]
于 2014-05-11T12:29:48.187 回答
22

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

希望这可以帮助!

于 2014-02-17T18:02:10.600 回答
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()
});
于 2012-07-28T03:09:32.480 回答
9

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

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

该文档仅涵盖 name 属性,但根据我的经验,该[JsonProperty]属性也完全隐藏了该属性所做的设置[DataMember]。因此,如果对您的情况可行,还可以将 Json.NET 属性添加到应忽略 [DataMember] 注释的属性中。

于 2014-04-08T09:17:45.797 回答
8

如果您想忽略DataContractAttribute所有类型的存在而不必添加其他属性,那么自定义合同解析器是正确的解决方案。但是,从 Json.NET 9.0.1开始, Amry 的解析器不再起作用。 Doolali 的解析器可以工作,但它具有序列化所有公共属性的额外副作用,包括标有[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;
        }
    }
}

您可能希望缓存合同解析器以获得最佳性能

于 2016-09-02T20:35:43.977 回答
-3

你试过这个吗?

忽略数据成员属性

于 2012-06-15T17:20:48.440 回答