NewtonSoft在runTime添加JSONIGNORE

时间:2014-08-06 10:04:01

标签: c# attributes json.net

我希望使用 NewtonSoft JSON 序列化列表,我需要在序列化时忽略其中一个属性,我得到以下代码

public class Car
{
  // included in JSON
  public string Model { get; set; }
  // ignored
  [JsonIgnore]
  public DateTime LastModified { get; set; }
}

但是我在我的应用程序中的许多地方使用此特定类别汽车,我想只在一个地方排除该选项。

我可以在我需要的特定位置动态添加[JsonIgnore]吗?我该怎么做?

7 个答案:

答案 0 :(得分:52)

不需要做其他答案中解释的复杂内容。

NewtonSoft JSON具有内置功能:

public bool ShouldSerializeINSERT_YOUR_PROPERTY_NAME_HERE()
{
    if(someCondition){
        return true;
    }else{
        return false;
    }
}

它被称为“条件属性序列化”和文档can be found here

警告:首先,摆脱[JsonIgnore]财产之上的{get;set;}非常重要。否则,它将覆盖ShouldSerializeXYZ行为。

答案 1 :(得分:19)

我认为最好使用自定义IContractResolver来实现这一目标:

public class DynamicContractResolver : DefaultContractResolver
{
    private readonly string _propertyNameToExclude;

    public DynamicContractResolver(string propertyNameToExclude)
    {
        _propertyNameToExclude = propertyNameToExclude;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);

        // only serializer properties that are not named after the specified property.
        properties =
            properties.Where(p => string.Compare(p.PropertyName, _propertyNameToExclude, true) != 0).ToList();

        return properties;
    }
}

LINQ可能不正确,我没有机会测试这个。然后您可以按如下方式使用它:

string json = JsonConvert.SerializeObject(car, Formatting.Indented,
   new JsonSerializerSettings { ContractResolver = new DynamicContractResolver("LastModified") });

有关详细信息,请参阅the documentation

答案 2 :(得分:8)

根据上面的@Underscore帖子,我创建了一个要在序列化时排除的属性列表。

public class DynamicContractResolver : DefaultContractResolver {
    private readonly string[] props;

    public DynamicContractResolver(params string[] prop) {
        this.props = prop;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) {
        IList<JsonProperty> retval = base.CreateProperties(type, memberSerialization);

        // retorna todas as propriedades que não estão na lista para ignorar
        retval = retval.Where(p => !this.props.Contains(p.PropertyName)).ToList();

        return retval;
    }
}

使用:

string json = JsonConvert.SerializeObject(car, Formatting.Indented, 
    new JsonSerializerSettings { ContractResolver = new DynamicContractResolver("ID", "CreatedAt", "LastModified") });

答案 3 :(得分:0)

试试这个:

    public static void IgnoreProperty<T, TR>(this T parameter, Expression<Func<T, TR>> propertyLambda)
    {
        var parameterType = parameter.GetType();
        var propertyName = propertyLambda.GetReturnedPropertyName();
        if (propertyName == null)
        {
            return;
        }

        var jsonPropertyAttribute = parameterType.GetProperty(propertyName).GetCustomAttribute<JsonPropertyAttribute>();
        jsonPropertyAttribute.DefaultValueHandling = DefaultValueHandling.Ignore;
    }

    public static string GetReturnedPropertyName<T, TR>(this Expression<Func<T, TR>> propertyLambda)
    {
        var member = propertyLambda.Body as MemberExpression;
        var memberPropertyInfo = member?.Member as PropertyInfo;
        return memberPropertyInfo?.Name;
    }

所以你可以这样做:

carObject.IgnoreProperty(so => so.LastModified);

答案 4 :(得分:0)

使用参考文献Dynamically rename or ignore properties without changing the serialized class,我们可以在运行时实现JsonIgnore。这是一个可行的解决方案。

例如考虑人物类:

public class Person
{
    // ignore property
    [JsonIgnore]
    public string Title { get; set; }

// rename property
[JsonProperty("firstName")]
public string FirstName { get; set; }
}

第1步:创建类“ PropertyRenameAndIgnoreSerializerContractResolver”

public class PropertyRenameAndIgnoreSerializerContractResolver : DefaultContractResolver
{
    private readonly Dictionary<Type, HashSet<string>> _ignores;
    private readonly Dictionary<Type, Dictionary<string, string>> _renames;

public PropertyRenameAndIgnoreSerializerContractResolver()
{
    _ignores = new Dictionary<Type, HashSet<string>>();
    _renames = new Dictionary<Type, Dictionary<string, string>>();
}

public void IgnoreProperty(Type type, params string[] jsonPropertyNames)
{
    if (!_ignores.ContainsKey(type))
        _ignores[type] = new HashSet<string>();

    foreach (var prop in jsonPropertyNames)
        _ignores[type].Add(prop);
}

public void RenameProperty(Type type, string propertyName, string newJsonPropertyName)
{
    if (!_renames.ContainsKey(type))
        _renames[type] = new Dictionary<string, string>();

    _renames[type][propertyName] = newJsonPropertyName;
}

protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
    var property = base.CreateProperty(member, memberSerialization);

    if (IsIgnored(property.DeclaringType, property.PropertyName))
    {
        property.ShouldSerialize = i => false;
        property.Ignored = true;
    }

    if (IsRenamed(property.DeclaringType, property.PropertyName, out var newJsonPropertyName))
        property.PropertyName = newJsonPropertyName;

    return property;
}

private bool IsIgnored(Type type, string jsonPropertyName)
{
    if (!_ignores.ContainsKey(type))
        return false;

    return _ignores[type].Contains(jsonPropertyName);
}

private bool IsRenamed(Type type, string jsonPropertyName, out string newJsonPropertyName)
{
    Dictionary<string, string> renames;

    if (!_renames.TryGetValue(type, out renames) || !renames.TryGetValue(jsonPropertyName, out newJsonPropertyName))
    {
        newJsonPropertyName = null;
        return false;
    }

    return true;
}
}

第2步:在您要应用Jsonignore的方法中添加代码

var person = new Person();
var jsonResolver = new PropertyRenameAndIgnoreSerializerContractResolver();

jsonResolver.IgnoreProperty(typeof(Person), "Title");
jsonResolver.RenameProperty(typeof(Person), "FirstName", "firstName");

var serializerSettings = new JsonSerializerSettings();
serializerSettings.ContractResolver = jsonResolver;

var json = JsonConvert.SerializeObject(person, serializerSettings);

答案 5 :(得分:0)

根据接受的答案,它会是这样的:

[JsonIgnore]
public bool JsonIgnore { get; set; }

public bool ImageModified { get; set; }

public bool ShouldSerializeImageModified() => !JsonIgnore;

每当 JsonIgnore 设置为 true 时,都意味着 ImageModified 不会被序列化,并且 JsonIgnore 由于 [JsonIgnore] 而被忽略。

如果需要以这种方式编写代码,这可能表明设计不佳。系统中可能需要有 DTO 或 ViewModel,除非您想动态禁用/启用某些属性的序列化。

答案 6 :(得分:0)

关于所有正确答案,我想补充一点。当您嵌套具有相同名称的属性时,忽略将影响具有相同名称的所有属性。如果您想忽略特定属性,您可以执行以下操作:

    public class DynamicContractResolver : DefaultContractResolver
    {
        private readonly string[] props;

        public DynamicContractResolver(params string[] prop)
        {
           this.props = prop;
        }

        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
           IList<JsonProperty> retval = base.CreateProperties(type, memberSerialization);
           return retval.Where(p => !this.props.Contains(p.DeclaringType.FullName + "." + p.PropertyName)).ToList();
        }
    }

然后当你想使用它时,你可以说:

var values = await _dbContext
                .Set<EntityName>()
                .Where(...).ToList();


            var json = JsonConvert.SerializeObject(values, Formatting.Indented,
                    new JsonSerializerSettings
                    {
                        ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                        ContractResolver = new DynamicContractResolver("Entities.Contact.Address1","Entities.User.Name","Entities.Event.Name")
                    });

地址 1 将在联系人中被忽略,而不是在其他任何地方。