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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11055225/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 16:18:21  来源:igfitidea点击:

Configure JSON.NET to ignore DataContract/DataMember attributes

c#jsonjson.netdatacontractdatamember

提问by Nick

We are running into a situation on an MVC3 project with both the Microsoft JSON serializers and JSON.NET.

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

Everybody knows DateTime's are basically broken in Microsoft's serializers, so we switched to JSON.NET to avoid this issue. That works great, except that some of the classes we are trying to serialize are POCOs with DataContract/DataMember attributes. They are defined in an assembly that is referenced in multiple places. Additionally, they have some other display properties that are not marked as DataMembers for efficiency. For instance, a Customer

每个人都知道 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; }
   }

}

When this customer is passed over WCF the client side can reference that assembly and use the FullName just fine, but when serialized with JSON.NET it sees that FullName isn't a [DataMember]and doesn't serialize it. Is there an option to pass to JSON.NET to tell it to ignore the fact that a class has [DataContract]attribute applied?

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

Note:Using the JavaScriptSerializer in .NET works fine for the FullName property, but DateTimes are broken. I need JSON.NET to ignore the fact that this class has DataContract/DataMember attributes and just do standard public field serialization like it would if they weren't there.

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

回答by duckus

Have you tried this?

你试过这个吗?

IgnoreDataMemberAttribute

忽略数据成员属性

回答by Amry

I was having a problem almost related to what you're having, and managed to find a solution by going through Json.NET's codes. So it may not be the best solution, but it works for me.

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

To do this, you need to implement your own IContractResolver. An over-simplified implementation of that to include all parameters and ignores all attributes (not just DataContractbut other built-in Json.NET's rules as well, so whatever options you set that should originally affect the members selection is now being overidden by this code):

为此,您需要实现自己的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();
    }
}

And here comes the code usage example:

下面是代码使用示例:

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

回答by Doolali

As Amry said you can uses your own IContractResolver.

正如 Amry 所说,您可以使用自己的 IContractResolver。

Unfortunately the solution provided by Amry didn't work for me, below is the solution that I managed to get working:

不幸的是,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;
    }
}

There are a few lines commented, these wern't required to make my solution work, but you never know!

有几行注释,这些不是使我的解决方案起作用所必需的,但你永远不知道!

This has the same usage as Amry's solution:

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

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

Hope this helps!

希望这可以帮助!

回答by rene

In accordance to the Json.NET documentation [DataMember]attributes are ignored if the properties are also annotated with Json.NET specific attributes (such as [JsonProperty]).See the Serialization Attributes documentationfor details:

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

Json.NET attributes take presidence over standard .NET serialization attributes, e.g. if both JsonPropertyAttribute and DataMemberAttribute are present on a property and both customize the name, the name from JsonPropertyAttribute will be used.

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

The documentation only covers the name property, but for my experience the [JsonProperty]attribute also fully shadows settings done by the [DataMember]attribute. So, if it is feasible for your case, also add Json.NET attributes to the properties for which the [DataMember] annotation should be ignored.

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

回答by seldary

Simply use Json.Net's OptOut attribute. It will take precedence over DataContract.

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

[DataContract]
[JsonObject(MemberSerialization.OptOut)]

回答by dbc

If you want to ignore the presence of DataContractAttributefor all types without having to add additional attributes, then a custom contract resolveris the correct solution. However, as of Json.NET 9.0.1 Amry's resolverno longer works. Doolali's resolverworks but it has the additional side effect of serializing allpublic properties including those marked with [JsonIgnore]. If you require a contract resolver that onlyignores the presence of DataContractAttributebut otherwise behaves like the default contract resolver, the following can be used:

如果您想忽略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;
        }
    }
}

You may want to cache the contract resolver for best performance.

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