как настроить NamingStrategy для newtonsoft json динамически?

134
20 января 2021, 09:40

Есть redmine. У него есть API. API этот для единичного элемента выглядит так

{
  "issue": { ... }
}

где "issue" это тип возвращаемой сущности. Для другой сущности это будет другое значение. Я хочу десериализовать это в тип

public class SingleEntity<T>
{
    public T Entity { get; set; }
}

Где T будет типом сущности. Понятное дело, в свойство Entity так просто ничего не десериализуется. Через NamingStrategy сделать не получится, потому что для именования мне потребуется тип T, но передать его в NamingStrategyParameters я не могу, потому что в атрибуте нельзя указывать typeof(T).

Вариант с ручной десериализацией через JObject мне не очень нравится. Хотя бы потому, что следующим шагом будет десериализация коллекций, а там все немного сложнее. В итоге код не будет выглядеть очевидным.

Вот я и подумал, может есть возможность настройки сериализации/десериализации для newtonsoft json в рантайме?

Answer 1

Мне кажется, вы ищете что то вроде этого:

Допустим есть класс

public class SingleResponse<T>
{       
    public T Entity {get;set;}
}

И вы определили типы

public class Issue
{
    [JsonProperty("project_id")]
    public int ProjectId{get;set;}
    public string Subject { get; set; }
}
public class User
{
    public string Login { get; set; }
}

Есть Json типа

string issueJ= @"{
  ""issue"": {
    ""project_id"": 1,
    ""subject"": ""Example"",
    ""priority_id"": 4
  }
}";
string userJ =  @"{
    ""user"": {
        ""login"": ""jplang"",
        ""firstname"": ""Jean-Philippe"",
        ""lastname"": ""Lang"",
        ""mail"": ""jp_lang@yahoo.fr"",
        ""password"": ""secret"" 
    }
}";

Тогда настрочим резолвер

public class CustomContractResolver : DefaultContractResolver
{
    private string _propertyName;
    public CustomContractResolver(string propertyName)
    {
        _propertyName = propertyName;
    }   
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);        
        if (property.PropertyName == "Entity")
        property.PropertyName = _propertyName;
        return property;
    }
}

и будем им пользоваться вот так

var serializerSettings = new JsonSerializerSettings()
{
    ContractResolver = new CustomContractResolver("issue")
};
var issue = JsonConvert.DeserializeObject<SingleResponse<Issue>>(issueJ, serializerSettings);
Console.WriteLine(issue.Entity.Subject);

serializerSettings = new JsonSerializerSettings()
{
    ContractResolver = new CustomContractResolver("user")
};
var user = JsonConvert.DeserializeObject<SingleResponse<User>>(userJ, serializerSettings);
Console.WriteLine(user.Entity.Login);

На выходе получим

Example
jplang

Мопед не мой, собран по мотивам этого поста

READ ALSO
Проблема с обновлением данных datagrid

Проблема с обновлением данных datagrid

Всем приветПрограмма для проведения соревнований

83
Постфиксный декремент

Постфиксный декремент

большая просьба помочь разобраться со следующим примером:

116
Удалить подстроку c#

Удалить подстроку c#

Текст самого задания: Отредактировать заданное предложение, удаляя из него все слова с нечетными номерами и переворачивая слова с четными...

98
Как сделать выборку MySQL чтобы значения в колонке содержали значения из списка

Как сделать выборку MySQL чтобы значения в колонке содержали значения из списка

Есть 2 таблицы, из одной я могу выбрать список нужных мне id:

110