.NET NewtonSoft JSON反序列化映射到不同的属性名

我有以下JSON字符串,这是从外部收到的。

{
"team":[
{
"v1":"",
"attributes":{
"eighty_min_score":"",
"home_or_away":"home",
"score":"22",
"team_id":"500"
}
},
{
"v1":"",
"attributes":{
"eighty_min_score":"",
"home_or_away":"away",
"score":"30",
"team_id":"600"
}
}
]
}

我的映射类:

public class Attributes
{
public string eighty_min_score { get; set; }
public string home_or_away { get; set; }
public string score { get; set; }
public string team_id { get; set; }
}


public class Team
{
public string v1 { get; set; }
public Attributes attributes { get; set; }
}


public class RootObject
{
public List<Team> team { get; set; }
}

问题是我不喜欢Team类中的Attributes 类名attributes 字段名称。相反,我希望它被命名为TeamScore,并从字段名称中删除_并给出适当的名称。

JsonConvert.DeserializeObject<RootObject>(jsonText);

我可以将Attributes重命名为TeamScore,但如果我更改字段名(Team类中的attributes),它将不会正确地反序列化并给我null。我怎样才能克服这个问题呢?

318762 次浏览

Json。NET - Newtonsoft有一个JsonPropertyAttribute,它允许你指定JSON属性的名称,所以你的代码应该是:

public class TeamScore
{
[JsonProperty("eighty_min_score")]
public string EightyMinScore { get; set; }
[JsonProperty("home_or_away")]
public string HomeOrAway { get; set; }
[JsonProperty("score ")]
public string Score { get; set; }
[JsonProperty("team_id")]
public string TeamId { get; set; }
}


public class Team
{
public string v1 { get; set; }
[JsonProperty("attributes")]
public TeamScore TeamScores { get; set; }
}


public class RootObject
{
public List<Team> Team { get; set; }
}

文档:Serialization Attributes .

如果您希望使用动态映射,并且不想让属性使您的模型变得混乱,那么这种方法对我来说是可行的

用法:

var settings = new JsonSerializerSettings();
settings.DateFormatString = "YYYY-MM-DD";
settings.ContractResolver = new CustomContractResolver();
this.DataContext = JsonConvert.DeserializeObject<CountResponse>(jsonString, settings);

逻辑:

public class CustomContractResolver : DefaultContractResolver
{
private Dictionary<string, string> PropertyMappings { get; set; }


public CustomContractResolver()
{
this.PropertyMappings = new Dictionary<string, string>
{
{"Meta", "meta"},
{"LastUpdated", "last_updated"},
{"Disclaimer", "disclaimer"},
{"License", "license"},
{"CountResults", "results"},
{"Term", "term"},
{"Count", "count"},
};
}


protected override string ResolvePropertyName(string propertyName)
{
string resolvedName = null;
var resolved = this.PropertyMappings.TryGetValue(propertyName, out resolvedName);
return (resolved) ? resolvedName : base.ResolvePropertyName(propertyName);
}
}

添加到杰克的解决方案。我需要使用JsonProperty和Serialize来反序列化,同时忽略JsonProperty(反之亦然)。ReflectionHelper和Attribute Helper只是获取属性列表或属性的Helper类。如果有人关心的话,我可以加上。使用下面的例子,你可以序列化视图模型并获得“Amount”,即使JsonProperty是“RecurringPrice”。

    /// <summary>
/// Ignore the Json Property attribute. This is usefule when you want to serialize or deserialize differently and not
/// let the JsonProperty control everything.
/// </summary>
/// <typeparam name="T"></typeparam>
public class IgnoreJsonPropertyResolver<T> : DefaultContractResolver
{
private Dictionary<string, string> PropertyMappings { get; set; }


public IgnoreJsonPropertyResolver()
{
this.PropertyMappings = new Dictionary<string, string>();
var properties = ReflectionHelper<T>.GetGetProperties(false)();
foreach (var propertyInfo in properties)
{
var jsonProperty = AttributeHelper.GetAttribute<JsonPropertyAttribute>(propertyInfo);
if (jsonProperty != null)
{
PropertyMappings.Add(jsonProperty.PropertyName, propertyInfo.Name);
}
}
}


protected override string ResolvePropertyName(string propertyName)
{
string resolvedName = null;
var resolved = this.PropertyMappings.TryGetValue(propertyName, out resolvedName);
return (resolved) ? resolvedName : base.ResolvePropertyName(propertyName);
}
}

用法:

        var settings = new JsonSerializerSettings();
settings.DateFormatString = "YYYY-MM-DD";
settings.ContractResolver = new IgnoreJsonPropertyResolver<PlanViewModel>();
var model = new PlanViewModel() {Amount = 100};
var strModel = JsonConvert.SerializeObject(model,settings);

模型:

public class PlanViewModel
{


/// <summary>
///     The customer is charged an amount over an interval for the subscription.
/// </summary>
[JsonProperty(PropertyName = "RecurringPrice")]
public double Amount { get; set; }


/// <summary>
///     Indicates the number of intervals between each billing. If interval=2, the customer would be billed every two
///     months or years depending on the value for interval_unit.
/// </summary>
public int Interval { get; set; } = 1;


/// <summary>
///     Number of free trial days that can be granted when a customer is subscribed to this plan.
/// </summary>
public int TrialPeriod { get; set; } = 30;


/// <summary>
/// This indicates a one-time fee charged upfront while creating a subscription for this plan.
/// </summary>
[JsonProperty(PropertyName = "SetupFee")]
public double SetupAmount { get; set; } = 0;




/// <summary>
/// String representing the type id, usually a lookup value, for the record.
/// </summary>
[JsonProperty(PropertyName = "TypeId")]
public string Type { get; set; }


/// <summary>
/// Billing Frequency
/// </summary>
[JsonProperty(PropertyName = "BillingFrequency")]
public string Period { get; set; }




/// <summary>
/// String representing the type id, usually a lookup value, for the record.
/// </summary>
[JsonProperty(PropertyName = "PlanUseType")]
public string Purpose { get; set; }
}

扩展Rentering.com的 answer,在需要处理许多类型的整个图的情况下,并且你正在寻找一个强类型的解决方案,这个类可以提供帮助,参见下面的用法(fluent)。它以每种类型的黑名单或白名单的方式运行。类型不能两者都是(要点 -也包含全局忽略列表)。

public class PropertyFilterResolver : DefaultContractResolver
{
const string _Err = "A type can be either in the include list or the ignore list.";
Dictionary<Type, IEnumerable<string>> _IgnorePropertiesMap = new Dictionary<Type, IEnumerable<string>>();
Dictionary<Type, IEnumerable<string>> _IncludePropertiesMap = new Dictionary<Type, IEnumerable<string>>();
public PropertyFilterResolver SetIgnoredProperties<T>(params Expression<Func<T, object>>[] propertyAccessors)
{
if (propertyAccessors == null) return this;


if (_IncludePropertiesMap.ContainsKey(typeof(T))) throw new ArgumentException(_Err);


var properties = propertyAccessors.Select(GetPropertyName);
_IgnorePropertiesMap[typeof(T)] = properties.ToArray();
return this;
}


public PropertyFilterResolver SetIncludedProperties<T>(params Expression<Func<T, object>>[] propertyAccessors)
{
if (propertyAccessors == null)
return this;


if (_IgnorePropertiesMap.ContainsKey(typeof(T))) throw new ArgumentException(_Err);


var properties = propertyAccessors.Select(GetPropertyName);
_IncludePropertiesMap[typeof(T)] = properties.ToArray();
return this;
}


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


var isIgnoreList = _IgnorePropertiesMap.TryGetValue(type, out IEnumerable<string> map);
if (!isIgnoreList && !_IncludePropertiesMap.TryGetValue(type, out map))
return properties;


Func<JsonProperty, bool> predicate = jp => map.Contains(jp.PropertyName) == !isIgnoreList;
return properties.Where(predicate).ToArray();
}


string GetPropertyName<TSource, TProperty>(
Expression<Func<TSource, TProperty>> propertyLambda)
{
if (!(propertyLambda.Body is MemberExpression member))
throw new ArgumentException($"Expression '{propertyLambda}' refers to a method, not a property.");


if (!(member.Member is PropertyInfo propInfo))
throw new ArgumentException($"Expression '{propertyLambda}' refers to a field, not a property.");


var type = typeof(TSource);
if (!type.GetTypeInfo().IsAssignableFrom(propInfo.DeclaringType.GetTypeInfo()))
throw new ArgumentException($"Expresion '{propertyLambda}' refers to a property that is not from type '{type}'.");


return propInfo.Name;
}
}

用法:

var resolver = new PropertyFilterResolver()
.SetIncludedProperties<User>(
u => u.Id,
u => u.UnitId)
.SetIgnoredProperties<Person>(
r => r.Responders)
.SetIncludedProperties<Blog>(
b => b.Id)
.Ignore(nameof(IChangeTracking.IsChanged)); //see gist

我在序列化时使用JsonProperty属性,但在使用ContractResolver反序列化时忽略它们:

public class IgnoreJsonPropertyContractResolver: DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
foreach (var p in properties) { p.PropertyName = p.UnderlyingName; }
return properties;
}
}

ContractResolver只是将每个属性设置回类属性名(从Shimmy的解决方案简化)。用法:

var airplane= JsonConvert.DeserializeObject<Airplane>(json,
new JsonSerializerSettings { ContractResolver = new IgnoreJsonPropertyContractResolver() });

如果你想忽略一些东西,用这个

  [JsonIgnore]
public int Id { get; set; }
[JsonProperty("id")]
Public string real_id { get; set; }