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

本文关键字:接口 定义 属性 net JSON 序列化 使用 | 更新日期: 2023-09-27 18:20:07

我有一个接口,其属性如下:

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

我希望在序列化所有实现类时忽略SecretProperty。但似乎我必须在属性的每个实现上定义JsonIgnore属性。有没有一种方法可以在不必向每个实现添加JsonIgnore属性的情况下实现这一点?我没有找到任何对我有帮助的序列化程序设置。

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

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

如何在使用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;
    }
}

在我的JsonSerializerSettings中使用这个InterfaceContractResolver,在任何接口中具有JsonIgnoreAttribute的所有属性也将被忽略,即使它们具有JsonPropertyAttribute(由于内部if块的顺序)。

在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

演示小提琴在这里和这里。

我相信这是在Json.NET 4.0.3中添加的,尽管发布说明中没有明确提到JsonIgnore

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

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

然而,正如Vitaly所指出的,当属性从声明接口的类的基类继承时,这是不起作用的。在这里演示小提琴。

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

您应该在类名前面添加[DataContract]

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