使用JSON.net进行序列化时忽略接口中定义的属性

时间:2012-01-13 11:06:56

标签: c# .net json.net

我有一个像这样的属性的接口:

public interface IFoo {
    // ...

    [JsonIgnore]
    string SecretProperty { get; }

    // ...
}

我希望在序列化所有实现类时忽略SecretProperty。但似乎我必须在属性的每个实现上定义JsonIgnore属性。有没有办法实现这一点,而无需为每个实现添加JsonIgnore属性?我没有找到任何帮助我的序列化设置。

4 个答案:

答案 0 :(得分:8)

经过一番搜索后,我发现了这个问题:

How to inherit the attribute from interface to object when serializing it using JSON.NET

我接受了Jeff Sternal的代码并添加了JsonIgnoreAttribute检测,所以它看起来像这样:

class InterfaceContractResolver : DefaultContractResolver
{
    public InterfaceContractResolver() : this(false) { }

    public InterfaceContractResolver(bool shareCache) : base(shareCache) { }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        var interfaces = member.DeclaringType.GetInterfaces();
        foreach (var @interface in interfaces)
        {
            foreach (var interfaceProperty in @interface.GetProperties())
            {
                // This is weak: among other things, an implementation 
                // may be deliberately hiding an interface member
                if (interfaceProperty.Name == member.Name && interfaceProperty.MemberType == member.MemberType)
                {
                    if (interfaceProperty.GetCustomAttributes(typeof(JsonIgnoreAttribute), true).Any())
                    {
                        property.Ignored = true;
                        return property;
                    }

                    if (interfaceProperty.GetCustomAttributes(typeof(JsonPropertyAttribute), true).Any())
                    {
                        property.Ignored = false;
                        return property;
                    }
                }
            }
        }

        return property;
    }
}

在我的InterfaceContractResolver中使用此JsonSerializerSettings,所有在任何界面中都有JsonIgnoreAttribute的属性也会被忽略,即使他们有JsonPropertyAttribute(由于内部if块的顺序。)

答案 1 :(得分:2)

我发现创建一个只有我想要的属性的DTO并将该对象序列化为JSON是最简单的。它创建了许多小的,特定于上下文的对象,但是管理代码库更容易,我不必考虑我正在序列化的内容与我忽略的内容。

答案 2 :(得分:1)

在Json.NET的最新版本中,将[JsonIgnore]应用于接口属性仅能正常工作,并成功地防止它们针对所有实现类型进行序列化。不再需要自定义合同解析器。

例如,如果我们定义以下类型:

public interface IFoo 
{
    [JsonIgnore]
    string SecretProperty  { get; set; }

    string Include { get; set; }
}

public class Foo : IFoo 
{
    public string SecretProperty  { get; set; }
    public string Include { get; set; }
}

然后,以下测试在Json.NET 11和12(以及可能更早的版本)中通过:

var root = new Foo
{
    SecretProperty  = "Ignore Me",
    Include = "Include Me",
};

var json = JsonConvert.SerializeObject(root);

Assert.IsTrue(json == "{\"Include\":\"Include Me\"}");// Passes

演示小提琴here

我相信Json.NET 4.0.3中已添加了此功能,尽管发行说明中未明确提及JsonIgnore

  

新功能-现在可以将JsonObject和JsonProperty属性放在接口上,并在序列化实现对象时使用。

(该实现可在JsonTypeReflector.GetAttribute<T>(MemberInfo memberInfo)中找到。)

答案 3 :(得分:-1)

您应该在班级名称前添加[DataContract]

它将默认值从包含所有属性更改为仅包括显式标记的属性。之后,在要包含在JSON输出中的每个属性前面添加“[DataMember]”。