.NET NewtonSoft JSON khử bản đồ thành một tên thuộc tính khác


294

Tôi đã theo chuỗi JSON được nhận từ một bên ngoài.

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

Các lớp ánh xạ của tôi:

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

Câu hỏi là tôi không thích Attributes tên lớpattributes tên trường trong Teamlớp. Thay vào đó, tôi muốn nó được đặt tên TeamScorevà cũng loại bỏ _khỏi tên trường và đặt tên thích hợp.

JsonConvert.DeserializeObject<RootObject>(jsonText);

Tôi có thể đổi tên Attributesthành TeamScore, nhưng nếu tôi thay đổi tên trường ( attributestrong Teamlớp), nó sẽ không được khử lưu đúng cách và cung cấp cho tôi null. Làm thế nào tôi có thể vượt qua điều này?


Câu trả lời:


572

Json.NET có một JsonPropertyAttributecho phép bạn chỉ định tên của một thuộc tính JSON, vì vậy mã của bạn phải là:

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

Tài liệu: Thuộc tính tuần tự hóa


2
Tôi có thể sử dụng hai JsonProperty cho một lần nộp không?
Ali Yousefi

1
@AliYousefie Đừng nghĩ vậy. Nhưng câu hỏi hay sẽ là, bạn mong đợi gì từ đó?
outcoldman

5
Tôi có một giao diện, hai lớp được sử dụng giao diện này, nhưng dữ liệu máy chủ có hai tên thuộc tính cho hai lớp, tôi muốn sử dụng hai JsonProperty cho một thuộc tính trong giao diện của mình.
Ali Yousefi

làm thế nào chúng ta có thể đảm bảo rằng phản hồi [đối tượng khử lưu lượng] có giá trị cho EightyMinScore chứ không phải tám mươi_min_score
Gaurravs

Trong trường hợp của tôi, tôi đang gửi RootObject dưới dạng phản hồi cuối cùng, nhưng khi tôi đọc nó dưới dạng json từ phản hồi cuối cùng, Eighty_min_score được hiển thị với giá trị chứ không phải với EightyMinScore
Gaurravs

115

Nếu bạn muốn sử dụng ánh xạ động và không muốn làm lộn xộn mô hình của mình với các thuộc tính, phương pháp này hiệu quả với tôi

Sử dụng:

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

Hợp lý:

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
Đã đơn giản hóa nó một chút cho mục đích của tôi nhưng đây là một giải pháp tốt hơn sau đó "làm lộn xộn mô hình / miền của bạn";)
Andreas

4
Ồ Đó là sử thi; kiến trúc âm thanh hơn nhiều cách làm việc đó.
David Betz

1
Nó có thể (nếu bạn tạo nhiều hơn một trong số này) đáng để di chuyển từ điển, tra cứu mã lên một lớp cơ sở cho tất cả các ánh xạ thuộc tính và cho phép chúng thêm thuộc tính nhưng bỏ qua các chi tiết về cách ánh xạ xảy ra. Có thể chỉ đáng để thêm nó vào chính Json.Net.
James White

Đây phải là câu trả lời chấp nhận được vì, như @DavidBetz nói, đó là thiết kế tốt nhất.
im1dermike

Liệu giải pháp này làm việc với các thuộc tính lồng nhau là tốt? Tôi đã cố gắng giải tuần tự hóa một đối tượng với các thuộc tính lồng nhau và nó không hoạt động.
Avi K.

8

Thêm vào giải pháp Jacks. Tôi cần Deserialize bằng cách sử dụng JsonProperty và serialize trong khi bỏ qua JsonProperty (hoặc ngược lại). ReflectionHelper và Attribution Helper chỉ là các lớp của trình trợ giúp có được danh sách các thuộc tính hoặc thuộc tính cho một thuộc tính. Tôi có thể bao gồm nếu bất cứ ai thực sự quan tâm. Sử dụng ví dụ bên dưới, bạn có thể tuần tự hóa viewmodel và nhận "Số tiền" mặc dù JsonProperty là "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);
        }
    }

Sử dụng:

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

Mô hình:

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
Cảm ơn IgnoreJsonPropertyResolver của bạn, vì tôi đang tìm cách làm điều tương tự (bỏ qua JsonProperty chỉ trên tuần tự hóa). Thật không may, giải pháp của bạn chỉ hoạt động cho các thuộc tính cấp cao nhất và các loại không lồng nhau. Cách thích hợp để bỏ qua tất cả các thuộc tính JsonProperty khi tuần tự hóa là ghi đè CreatePropertytrong ContractResolver. Có gọi cơ sở: var jsonProperty = base.CreateProperty(memberInfo, memberSerialization);và sau đó thiết lập jsonProperty.PropertyName = memberInfo.Name;. Cuối cùng, return jsonProperty;đó là tất cả những gì bạn cần.
Nate Cook

1
Những người giúp việc này là gì?
deadManN

1
@NateCook bạn có thể cho tôi xem một mẫu? tôi cần nó ngay bây giờ
deadManN

4

Mở rộng câu trả lời của Rentering.com , trong các tình huống cần phải quan tâm đến toàn bộ biểu đồ gồm nhiều loại và bạn đang tìm kiếm một giải pháp được gõ mạnh, lớp này có thể giúp, xem cách sử dụng (lưu loát) bên dưới. Nó hoạt động như một danh sách đen hoặc danh sách trắng cho mỗi loại. Một loại không thể là cả hai ( Gist - cũng chứa danh sách bỏ qua toàn cầu).

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

Sử dụng:

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

0

Tôi đang sử dụng các thuộc tính JsonProperty khi tuần tự hóa nhưng bỏ qua chúng khi giải tuần tự hóa bằng cách sử dụng này 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;
        }
    }

Chỉ ContractResolvercần đặt mọi thuộc tính trở lại tên thuộc tính lớp (được đơn giản hóa từ giải pháp Shimmy). Sử dụng:

var airplane= JsonConvert.DeserializeObject<Airplane>(json, 
    new JsonSerializerSettings { ContractResolver = new IgnoreJsonPropertyContractResolver() });
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.