JsonIgnore属性是条件模拟而不是ShouldSerialize

时间:2017-06-28 17:36:59

标签: c# json attributes

我想在C#中实现[JsonIgnore]属性的条件版本。我不想使用ShouldSerializePropertyName,因为它依赖于硬编码的属性名称。

我的API模型继承自数据库模型,我当然希望忽略数据库ID,但我也想根据客户支付的功能忽略其他一些属性。我不想使用ShouldSerialize技术,因为我的团队中的其他开发人员可能会更改数据库属性名称并意外地显示不应该看到的内容。

我看了if I can optionally turn off the JsonIgnore attribute at runtime

但看起来建议的技术会关闭所有JsonIgnore。我想要做的是根据某些条件关闭其中一些。

有解决方法吗?是否有某些属性可以做到这一点?如果我需要编写自定义属性,你能告诉我怎么样吗?谢谢!

1 个答案:

答案 0 :(得分:1)

这是一个有趣的问题。我的回答大量借鉴了您提供的链接,但检查了定义“高级内容”的自定义属性(用户支付的费用):

与您的链接一样,我定义了一个类Foo,它将被序列化。它包含一个子对象PremiumStuff,其中包含只有在用户付费时才应序列化的内容。我已使用自定义属性PremiumContent标记了此子对象,该属性也在此代码段中定义。然后我使用了一个继承自DefaultContractResolver的自定义类,就像链接一样,但是在这个实现中,我正在检查每个属性的自定义属性,并且仅在if块中运行代码属性标记为PremiumContent。此条件代码检查名为AllowPremiumContent的静态bool,以查看我们是否允许序列化高级内容。如果不允许,那么我们将Ignore标志设置为true:

class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }
    [JsonIgnore]
    public string AlternateName { get; set; }
    [PremiumContent]
    public PremiumStuff ExtraContent { get; set; }
}

class PremiumStuff
{
    public string ExtraInfo { get; set; }
    public string SecretInfo { get; set; }
}

class IncludePremiumContentAttributesResolver : DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
        foreach (var prop in props)
        {
            if (Attribute.IsDefined(type.GetProperty(prop.PropertyName), typeof(PremiumContent)))
            {
                //if the attribute is marked with [PremiumContent]

                if (PremiumContentRights.AllowPremiumContent == false)
                {
                    prop.Ignored = true;   // Ignore this if PremiumContentRights.AllowPremiumContent is set to false
                }
            }
        }
        return props;
    }
}

[System.AttributeUsage(System.AttributeTargets.All)]
public class PremiumContent : Attribute
{
}

public static class PremiumContentRights
{
    public static bool AllowPremiumContent = true;
}

现在,让我们实现这一点,看看我们得到了什么。这是我的测试代码:

PremiumContentRights.AllowPremiumContent = true;
Foo foo = new Foo()
{
    Id = 1,
    Name = "Hello",
    AlternateName = "World",
    ExtraContent = new PremiumStuff()
    {
        ExtraInfo = "For premium",
        SecretInfo = "users only."
    }
};

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new IncludePremiumContentAttributesResolver();
settings.Formatting = Formatting.Indented;

string json = JsonConvert.SerializeObject(foo, settings);

Debug.WriteLine(json);

在第一行中,PremiumContentRights.AllowPremiumContent设置为true,这是输出:

{
  "Id": 1,
  "Name": "Hello",
  "ExtraContent": {
    "ExtraInfo": "For premium",
    "SecretInfo": "users only."
  }
}

如果我们将AllowPremiumContent设置为False并再次运行代码,则输出结果如下:

{
  "Id": 1,
  "Name": "Hello"
}

如您所见,ExtraContent属性包含在内或被忽略,具体取决于AllowPremiumContent变量的状态。