NewtonSoft add JSONIGNORE at runTime

懵懂的女人 提交于 2019-12-17 07:27:54

问题


Am looking to Serialize a list using NewtonSoft JSON and i need to ignore one of the property while Serializing and i got the below code

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

But am using this Specific class Car in many places in my application and i want to Exclude the option only in one place.

Can i dynamically add [JsonIgnore] in the Specific Place where i need ? How do i do that ?


回答1:


No need to do the complicated stuff explained in the other answer.

NewtonSoft JSON has a built-in feature for that:

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

It is called "conditional property serialization" and the documentation can be found here.

Warning: first of all, it is important to get rid of [JsonIgnore] above your {get;set;} property. Otherwise it will overwrite the ShouldSerializeXYZ behavior.




回答2:


I think it would be best to use a custom IContractResolver to achieve this:

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;
    }
}

The LINQ may not be correct, I haven't had a chance to test this. You can then use it as follows:

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

Refer to the documentation for more information.




回答3:


Based on @Underscore post above, I created a list of properties to exclude on serialization.

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;
    }
}

Use:

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



回答4:


Try this:

    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;
    }

So you can do this:

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



回答5:


With the reference Dynamically rename or ignore properties without changing the serialized class we can achieve JsonIgnore at run time. It's a workable solution.

Consider Person Class for example:

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

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

Step 1: Create Class "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;
}
}

Step 2: Add code in your method where Jsonignore want to apply

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);


来源:https://stackoverflow.com/questions/25157511/newtonsoft-add-jsonignore-at-runtime

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!