我想使用NewtonSoft JSON序列化列表,在序列化时我需要忽略其中一个属性,我得到了以下代码
public class Car
{
// included in JSON
public string Model { get; set; }
// ignored
[JsonIgnore]
public DateTime LastModified { get; set; }
}
但是在我的应用程序中,我在很多地方使用这个特定类别的汽车,我想只在一个地方排除这个选项。
我可以在需要的特定位置动态添加[JsonIgnore]吗?我该怎么做?
不需要做另一个答案中解释的复杂事情。
NewtonSoft JSON有一个内置功能:
public bool ShouldSerializeINSERT_YOUR_PROPERTY_NAME_HERE()
{
if(someCondition){
return true;
}else{
return false;
}
}
它被称为"条件属性序列化",文档可以在这里找到。
警告:首先,清除{get;set;}
属性之上的[JsonIgnore]
非常重要。否则,它将覆盖ShouldSerializeXYZ
行为。
我认为最好使用自定义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") });
有关更多信息,请参阅文档。
基于上面的@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);
// return all the properties which are not in the ignore list
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") });
通过引用在不更改序列化类的情况下动态重命名或忽略属性,我们可以在运行时实现JsonIgnore。这是一个可行的解决方案。
以人员类别为例:
public class Person
{
// ignore property
[JsonIgnore]
public string Title { get; set; }
// rename property
[JsonProperty("firstName")]
public string FirstName { get; set; }
}
步骤1:创建类"PropertyRenameAndIgnoreSerizerContractResolver">
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);
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")
});
Address1将在Contact中被忽略,而不是在其他任何位置。
试试这个:
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);
根据接受的答案,它会是:
[JsonIgnore]
public bool JsonIgnore { get; set; }
public bool ImageModified { get; set; }
public bool ShouldSerializeImageModified() => !JsonIgnore;
只要JsonIgnore
设置为true,就意味着ImageModified
不会被序列化,而JsonIgnore
由于[JsonIgnore]
而被忽略。
如果需要以这种方式编写代码,这可能表明设计不好。系统中可能需要DTO或ViewModel,除非您希望动态禁用/启用某些属性的序列化。