【问题标题】:JsonIgnore attribute conditional analog but not ShouldSerializeJsonIgnore 属性条件模拟但不是 ShouldSerialize
【发布时间】:2017-12-02 05:10:35
【问题描述】:

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

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

我读过if I can optionally turn off the JsonIgnore attribute at runtime

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

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

【问题讨论】:

  • 如果你不想使用硬编码的方法名,你想做什么?具有指定属性名称的静态方法?具有属性指定名称的实例方法?或者完全不需要向您的类型添加 Json.NET 属性的运行时? Conditional member serialization based on query parameter? 是你需要的吗?

标签: c# json attributes


【解决方案1】:

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

像你的链接一样,我定义了一个类Foo,它将被序列化。它包含一个子对象PremiumStuff,其中包含只有在用户付费时才应该序列化的东西。我已经用自定义属性PremiumContent 标记了这个子对象,该属性也在这段代码 sn-p 中定义。然后我使用了一个从DefaultContractResolver 继承的自定义类,就像链接一样,但是在这个实现中,我正在检查我们的自定义属性的每个属性,并且只有在属性标记为时才在if 块中运行代码PremiumContent。此条件代码检查名为AllowPremiumContent 的静态布尔值,以查看我们是否允许对高级内容进行序列化。如果不允许,那么我们将 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 变量的状态。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-26
  • 2017-09-03
  • 1970-01-01
相关资源
最近更新 更多