.NET NewtonSoft JSON, farklı bir özellik adına olan haritanın serisini kaldırır


294

Harici bir partiden alınan aşağıdaki JSON dizesi var.

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

Haritalama sınıflarım:

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

Soru sevmem ki Attributes sınıf adını ve attributes alan adlarını içinde Teamsınıfında. Bunun yerine, adlandırılmasını TeamScoreve _alan adlarından kaldırılmasını ve uygun adlar vermesini istiyorum.

JsonConvert.DeserializeObject<RootObject>(jsonText);

Ben yeniden adlandırabilir Attributesiçin TeamScore, ama (alan adını değiştirirseniz attributesiçinde Teamsınıfından), düzgün serisini ve bana verir vermez null. Bunun üstesinden nasıl gelebilirim?


Yanıtlar:


572

Json.NET , bir JsonPropertyAttributeJSON özelliğinin adını belirtmenize izin veren bir kod içerir, bu nedenle kodunuz şöyle olmalıdır:

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

Belgeler: Serileştirme Özellikleri


2
biri için iki JsonProperty kullanabilir miyim?
Ali Yousefi

1
@AliYousefie Düşünme. Ama iyi soru şu olacak, bundan ne elde etmeyi umuyorsunuz?
outcoldman

5
bir arabirim var, iki sınıf bu arabirim kullanılır, ancak sunucu verileri iki sınıf için iki özellik adı var, ben arayüzlerimde bir özellik için iki JsonProperty kullanmak istiyorum.
Ali Yousefi

[deserilized object] yanıtı sekizy_min_score için değil EightyMinScore için değere sahip olduğundan nasıl emin olabiliriz
Gaurravs

Benim durumumda RootObject'i nihai yanıt olarak gönderiyorum, ancak son yanıttan json olarak okuduğumda, sekizy_dak_score değerle gösteriliyor ve EightyMinScore
Gaurravs ile

115

Dinamik eşleme kullanmak istiyorsanız ve modelinizi niteliklerle karıştırmak istemiyorsanız, bu yaklaşım benim için çalıştı

Kullanımı:

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

Mantık:

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
Benim amacım için biraz basitleştirdi ama bu daha sonra "model / etki alanı dağınıklık" daha iyi bir çözümdür;)
Andreas

4
Vay. Bu destansı; çok daha mimari açıdan sağlam bir şekilde yapıyor.
David Betz

1
(Bunlardan birden fazlasını oluşturursanız) sözlüğü taşımaya değer olabilir, tüm özellik eşlemeleri için bir temel sınıfa arama kodu ekleyebilir ve özellik eklemelerine izin verebilir, ancak eşlemenin nasıl gerçekleştiğinin ayrıntılarını göz ardı edebilir. Bunu Json.Net'in kendisine eklemeye değebilir.
James White

Bu kabul edilebilir bir cevap olmalı çünkü @DavidBetz'in dediği gibi, bu en iyi tasarım.
im1dermike

Bu çözüm yuvalanmış özelliklerle de çalışır mı? Yuvalanmış özellikleri olan bir nesnenin serisini kaldırmaya çalıştım ve çalışmıyor.
Avi K.

8

Jacks çözümüne ekleme. JsonProperty (ya da tam tersi) göz ardı ederken JsonProperty ve Serialize kullanarak Deserialize gerekir. ReflectionHelper ve Attribute Helper, yalnızca bir özellik için özelliklerin veya özniteliklerin listesini alan yardımcı sınıflardır. Herkesin umurunda olup olmadığını dahil edebilirim. Aşağıdaki örneği kullanarak, JsonProperty "Yinelenen Fiyat" olsa bile, görünüm modelini serileştirebilir ve "Miktar" elde edebilirsiniz.

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

Kullanımı:

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

Model:

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
Aynı şeyi yapmak istediğim için IgnoreJsonPropertyResolver'ınız için teşekkürler (sadece serileştirmede JsonProperty'yi yoksayın). Maalesef çözümünüz yalnızca üst düzey özellikler için çalışır, yuvalanmış türler için geçerli değildir. Serileştirirken tüm JsonProperty niteliklerini yok saymanın uygun yolu CreatePropertyContractResolver'da geçersiz kılmaktır . Orada base: var jsonProperty = base.CreateProperty(memberInfo, memberSerialization);ve sonra ayarlayın jsonProperty.PropertyName = memberInfo.Name;. Sonunda return jsonProperty;ihtiyacınız olan tek şey bu.
Nate Cook

1
bu yardımcılar neler?
deadManN

1
@NateCook bana bir örnek gösterebilir misin? Şu anda kötü ihtiyacım var
deadManN

4

Rentering.com'un cevabını genişleterek , birçok türde bir grafiğin tamamının ele alınacağı senaryolarda ve güçlü bir şekilde yazılmış bir çözüm arıyorsanız, bu sınıf yardımcı olabilir, aşağıdaki kullanıma (akıcı) bakın. Her tür için bir kara liste veya beyaz liste olarak çalışır. Tür her ikisi de olamaz ( Gist - ayrıca genel yoksay listesi de içerir).

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

Kullanımı:

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

Serileştirme ama bu kullanarak serisini kaldırırken onları görmezden JsonProperty öznitelikleri kullanıyorum 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;
        }
    }

ContractResolverSadece (Shimmy en çözeltisinden basitleştirilmiş) sınıfı özellik adına her özellik geri ayarlar. Kullanımı:

var airplane= JsonConvert.DeserializeObject<Airplane>(json, 
    new JsonSerializerSettings { ContractResolver = new IgnoreJsonPropertyContractResolver() });
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.