.NET NewtonSoft JSON deserializa el mapa a un nombre de propiedad diferente

Tengo la siguiente cadena JSON que se recibe de una parte externa.

{ "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" } } ] } 

Mis clases de mapeo:

 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 { get; set; } } 

La pregunta es que no me gustan la “clase de atributo” y el “nombre de campo de atributos” en la clase de equipo. En su lugar, quiero que se denomine como “TeamScore” y también para eliminar “_” de los nombres de campo y dar nombres propios.

 JsonConvert.DeserializeObject(jsonText); 

Puedo cambiar la clase “Atributo” a “TeamScore”, pero si cambio el nombre archivado (atributos en la clase de equipo), no se deserializará correctamente y me dará nulo. ¿Cómo puedo superar esto?

Json.NET tiene un JsonPropertyAttribute que le permite especificar el nombre de una propiedad JSON, por lo que su código debería ser:

 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 { get; set; } } 

Documentación: Atributos de serialización

Si desea utilizar el mapeo dynamic, y no quiere desordenar su modelo con atributos, este enfoque funcionó para mí

Uso:

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

Lógica:

 public class CustomContractResolver : DefaultContractResolver { private Dictionary PropertyMappings { get; set; } public CustomContractResolver() { this.PropertyMappings = new Dictionary { {"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); } } 

Añadiendo a la solución Jacks. Necesito deserializar usando JsonProperty y Serialize mientras ignoro JsonProperty (o viceversa). ReflectionHelper y Attribute Helper son solo clases de ayuda que obtienen una lista de propiedades o atributos para una propiedad. Puedo incluir si a alguien realmente le importa. Usando el ejemplo a continuación, puede serializar el modelo de vista y obtener “Cantidad” aunque el JsonProperty sea “Precio recurrente”.

  ///  /// Ignore the Json Property attribute. This is usefule when you want to serialize or deserialize differently and not /// let the JsonProperty control everything. ///  ///  public class IgnoreJsonPropertyResolver : DefaultContractResolver { private Dictionary PropertyMappings { get; set; } public IgnoreJsonPropertyResolver() { this.PropertyMappings = new Dictionary(); var properties = ReflectionHelper.GetGetProperties(false)(); foreach (var propertyInfo in properties) { var jsonProperty = AttributeHelper.GetAttribute(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); } } 

Uso:

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

Modelo:

 public class PlanViewModel { ///  /// The customer is charged an amount over an interval for the subscription. ///  [JsonProperty(PropertyName = "RecurringPrice")] public double Amount { get; set; } ///  /// 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. ///  public int Interval { get; set; } = 1; ///  /// Number of free trial days that can be granted when a customer is subscribed to this plan. ///  public int TrialPeriod { get; set; } = 30; ///  /// This indicates a one-time fee charged upfront while creating a subscription for this plan. ///  [JsonProperty(PropertyName = "SetupFee")] public double SetupAmount { get; set; } = 0; ///  /// String representing the type id, usually a lookup value, for the record. ///  [JsonProperty(PropertyName = "TypeId")] public string Type { get; set; } ///  /// Billing Frequency ///  [JsonProperty(PropertyName = "BillingFrequency")] public string Period { get; set; } ///  /// String representing the type id, usually a lookup value, for the record. ///  [JsonProperty(PropertyName = "PlanUseType")] public string Purpose { get; set; } } 

Al expandir la respuesta de Rentering.com , en escenarios donde se debe tener en cuenta un gráfico completo de muchos tipos, y está buscando una solución fuertemente tipada, esta clase puede ayudar, vea el uso (fluido) a continuación. Funciona como una lista negra o lista blanca por tipo. Un tipo no puede ser ambos ( Gist – también contiene una lista global de ignorar).

 public class PropertyFilterResolver : DefaultContractResolver { const string _Err = "A type can be either in the include list or the ignore list."; Dictionary> _IgnorePropertiesMap = new Dictionary>(); Dictionary> _IncludePropertiesMap = new Dictionary>(); public PropertyFilterResolver SetIgnoredProperties(params Expression>[] 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(params Expression>[] 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 CreateProperties(Type type, MemberSerialization memberSerialization) { var properties = base.CreateProperties(type, memberSerialization); var isIgnoreList = _IgnorePropertiesMap.TryGetValue(type, out IEnumerable map); if (!isIgnoreList && !_IncludePropertiesMap.TryGetValue(type, out map)) return properties; Func predicate = jp => map.Contains(jp.PropertyName) == !isIgnoreList; return properties.Where(predicate).ToArray(); } string GetPropertyName( Expression> 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; } } 

Uso:

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