2013-04-10 97 views
196

我有以下JSON字符串從外部方接收。.NET NewtonSoft 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; } 
} 

的問題是,我不喜歡「屬性類」,並在團隊類中的「屬性字段名」。相反,我希望它被命名爲「TeamScore」,並從字段名稱中刪除「_」並給出正確的名稱。

JsonConvert.DeserializeObject<RootObject>(jsonText); 

我可以改變的「屬性」級到「TeamScore」,但如果我改變申請的域名(在Team類屬性),它將無法正常反序列化,給我空。我該如何克服這一點?

回答

403

Json.NETJsonPropertyAttribute它允許你指定一個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

+0

清除,簡潔的答案。尼斯。謝謝。也幫助了我。 FYI/Q?:輸入錯誤 [JsonProperty(「team)id」] ...應該是下劃線? – Aidanapword 2013-11-15 11:26:16

+2

我可以使用兩個JsonProperty的一個提交? – 2015-05-11 19:56:55

+0

@AliYousefie不這麼認爲。但好的問題是,你期望從中得到什麼? – outcoldman 2015-07-06 20:02:53

65

如果您想使用動態映射,並不想混亂你的模型與屬性,這種方法對我來說

用法:

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); 
    } 
} 
+1

爲我的目的做了簡化,但這是一個更好的解決方案,然後「混亂你模型/域」;) – Andreas 2015-07-30 08:44:43

+3

哇。這是史詩;更多的架構上合理的做法。 – 2015-12-11 02:53:03

+1

它可能(如果你創建了其中一個以上的)值得移動字典,查找代碼到所有屬性映射的基類,並讓它們添加屬性,但忽略映射發生的細節。可能值得把它添加到Json.Net本身。 – 2015-12-30 14:32:39

3

添加到插座溶液。我需要反序列化使用JsonProperty和序列化,而忽略JsonProperty(反之亦然)。 ReflectionHelper和Attribute Helper只是幫助程序類,它們可以獲取屬性的屬性或屬性列表。如果有人真的關心,我可以包括在內。使用下面的示例,即使JsonProperty是「RecurringPrice」,也可以序列化ViewModel並獲取「Amount」。

/// <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; } 
} 
+2

感謝您的IgnoreJsonPropertyResolver,因爲我期望做同樣的事情(僅在序列化時忽略JsonProperty)。不幸的是,您的解決方案僅適用於頂級屬性而不適用於嵌套類型。序列化時忽略所有JsonProperty屬性的正確方法是在ContractResolver中重寫'CreateProperty'。有調用基地:'var jsonProperty = base.CreateProperty(memberInfo,memberSerialization);'然後設置'jsonProperty.PropertyName = memberInfo.Name;'。最後'返回jsonProperty;'這就是你需要的。 – 2015-12-18 18:40:39

+0

這些幫手是什麼? – deadManN 2016-07-24 13:11:26

+1

@NateCook你可以給我看一個樣品嗎?我現在非常需要它 – deadManN 2016-07-24 13:14:48

1

擴大Rentering.com's答案,在場景中多種類型的整個圖形是被照顧的,你正在尋找對於強類型的解決方案,該類可以提供幫助,請參閱下面的使用(流利)。它以每種類型的黑名單或白名單的形式運作。一個類型不能同時爲(Gist - 也包含全局忽略列表)。

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 
相關問題