После десериализованных json-данных все объекты будут иметь значение null [duplicate]

Библиотека прикладного кода байтов Apache - ваш друг.

http://commons.apache.org/bcel/

225
задан Peter Mortensen 18 April 2017 в 20:18
поделиться

4 ответа

Json.NET имеет 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; }
}

Документация: Атрибуты сериализации

452
ответ дан K48 15 August 2018 в 19:25
поделиться
  • 1
    Ясный, лаконичный ответ. Ницца. Благодарю. Помог мне тоже. FYI / Q ?: typo в [JsonProperty (идентификатор команды)] должен быть подчеркиванием? – Aidanapword 15 November 2013 в 13:26
  • 2
    могу ли я использовать два JsonProperty для одной подачи? – Ali Yousefie 11 May 2015 в 19:56
  • 3
    @AliYousefie Не думайте так. Но хороший вопрос будет, что вы ожидаете от этого? – outcoldman 6 July 2015 в 20:02
  • 4
    У меня есть интерфейс, два класса используют этот интерфейс, но данные сервера имеют два имени свойства для двух классов, я хочу использовать два JsonProperty для одного свойства в моих интерфейсах. – Ali Yousefie 7 April 2016 в 06:35

Расширение ответа Rentering.com в сценариях, где нужно позаботиться о целом графике многих типов, и вы ищете строго типизированное решение, этот класс может помочь, см. использование (свободно). Он работает как черный список или белый список для каждого типа. Тип не может быть одновременно ( 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
1
ответ дан Community 15 August 2018 в 19:25
поделиться

Если вы хотите использовать динамическое сопоставление и не хотите загромождать свою модель атрибутами, этот подход работал для меня

Использование:

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);
    }
}
74
ответ дан Jack 15 August 2018 в 19:25
поделиться
  • 1
    Упростил это немного для моей цели, но это лучшее решение, а затем «загромождать вашу модель / домен». ;) – Andreas 30 July 2015 в 08:44
  • 2
    Вау. Это эпос; гораздо более архитектурно продуманный способ сделать это. – David Betz 11 December 2015 в 03:53
  • 3
    Он мог бы (если вы создадите более одного из них) стоит переместить словарь, код поиска до базового класса для всех сопоставлений свойств и позволить им добавлять свойства, но игнорировать детали того, как происходит сопоставление. Не стоит просто добавлять это в Json.Net. – James White 30 December 2015 в 15:32
  • 4
    Это должен быть приемлемый ответ, потому что, как сказал @DavidBetz, это лучший дизайн. – im1dermike 29 January 2016 в 15:46
  • 5
    Поддерживает ли это решение работу с вложенными свойствами? Я попытался десериализовать объект с вложенными свойствами, и он не работает. – Avi K. 29 June 2016 в 09:54

Добавление к решению Jacks. Мне нужно Deserialize, используя JsonProperty и Serialize, игнорируя JsonProperty (или наоборот). ReflectionHelper и Attribute Helper - это только вспомогательные классы, которые получают список свойств или атрибутов для свойства. Я могу включить, если кто-то действительно заботится. Используя приведенный ниже пример, вы можете сериализовать viewmodel и получить «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; }
}
3
ответ дан Rentering.com 15 August 2018 в 19:25
поделиться
  • 1
    Спасибо за ваш IgnoreJsonPropertyResolver, так как я искал сделать то же самое (игнорируйте JsonProperty только при сериализации). К сожалению, ваше решение работает только для атрибутов верхнего уровня, а не для вложенных типов. Правильный способ игнорировать все атрибуты JsonProperty при сериализации - это переопределить CreateProperty в ContractResolver. Там вызывается база: var jsonProperty = base.CreateProperty(memberInfo, memberSerialization);, а затем установите jsonProperty.PropertyName = memberInfo.Name;. Наконец, return jsonProperty; Это все, что вам нужно. – Nate Cook 18 December 2015 в 19:40
  • 2
    что это за помощники? – deadManN 24 July 2016 в 13:11
  • 3
    @NateCook вы можете показать мне образец? мне это очень плохо сейчас – deadManN 24 July 2016 в 13:14
Другие вопросы по тегам:

Похожие вопросы: