Разбор json из внешнего Api

В настоящее время я пишу библиотеку C# оболочки для внешнего REST API (который у меня нет контроля), который возвращает JSON.

Для десериализации следующего JSON

{
    "countries": {
        "2": {
            "name": "Albania",
            "isoCode": "AL",
            "dialCode": "+355"
        },
        "3": {
            "name": "Algeria",
            "isoCode": "DZ",
            "dialCode": "+213"
        },
        "4": {
            "name": "American Samoa",
            "isoCode": "AS",
            "dialCode": "+1684"
        }
    }
}

У меня есть метод GetCountries в моей библиотеке, который выполняет следующие действия:

public List GetCountries()
{
  string endpointUrl = GenerateEndPointUri(...)

  var countries = IssueApiGETRequest(endpointUrl);

  return countries.Countries.Select(x =>
  {
    x.Value.Id = x.Key;
    return x.Value;
  }).ToList();
}

IssueAPIGetRequest выглядит примерно так:

private T IssueApiGETRequest(string endPointUrl)
{
  using (var handler = new HttpClientHandler())
  {
    handler.Credentials = ...;

    using (HttpClient client = new HttpClient(handler))
    {
      var response = client.GetAsync(endPointUrl).Result;

      if (response.IsSuccessStatusCode)
      {
        string json = response.Content.ReadAsStringAsync().Result;
        var result = JsonConvert.DeserializeObject(json);

        return result;
      }
      else
      {
        switch (response.StatusCode)
        {
          case HttpStatusCode.BadRequest:
            throw new InvalidParameterException("Invalid parameters");
        }
        throw new Exception("Unable to process request");
      }
    }
  }
}

Это позволяет мне определить общий метод для всех конечных точек GET во внешнем API и сделать их сериализованными в мои собственные определенные типы.

Затем, наконец, я определил эти объекты класса:

  [JsonObject(MemberSerialization = MemberSerialization.OptIn)]
  internal class CountriesWrapper
  {
    [JsonProperty(PropertyName = "countries")]
    public IDictionary Countries { get; set; }
  }

  [JsonObject(MemberSerialization = MemberSerialization.OptIn)]
  public class Country
  {
    public int Id { get; set; }

    [JsonProperty(PropertyName = "name")]
    public string Name { get; set; }

    [JsonProperty(PropertyName = "isoCode")]
    public string IsoCode { get; set; }

    [JsonProperty(PropertyName = "dialCode")]
    public string DialCode { get; set; }
  }

Я не очень доволен методом GetCountries, который должен повторить словарь, который возвращается из десериализации, и имеющий класс CountryWrapper .

QUESTION: I would like to know if I'm missing a trick or if someone can suggest a cleaner way of laying this out. Whilst keeping a generic method of issuing GET requests to the external API.

0
nl ja de

1 ответы

Это можно сделать с помощью JsonConverter, подобным этому answer

Я думаю, что это очень странный json, так или иначе я внедрил Конвертер, который может читать этот тип json. Я не думаю, что это хорошо реализовано, но вы можете улучшить его

class CountriesConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(List));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var l = new List();
        dynamic expando = new ExpandoObject();
        var temp = expando as IDictionary;
        if (reader.TokenType == JsonToken.StartObject)
        {
            var newCountry = true;
            while (reader.TokenType != JsonToken.EndObject)
            {
                if(newCountry)
                    reader.Read();
                if (reader.TokenType == JsonToken.PropertyName)
                {
                    if (reader.Value != null && reader.Value.ToString() != "countries")
                    {
                        if (!temp.ContainsKey("Id"))
                        {
                            newCountry = true;
                            int id = 0;
                            if (Int32.TryParse(reader.Value.ToString(), out id))
                                temp.Add("Id", id);
                        }
                        else
                        {
                            var propertyName = reader.Value.ToString();
                            reader.Read();
                            temp.Add(propertyName, reader.Value.ToString());
                        }

                    }
                }
                else if (reader.TokenType == JsonToken.EndObject)
                {
                    l.Add(Country.BuildCountry(expando));
                    temp.Clear();
                    reader.Read();
                    newCountry = false;
                }
            }
            reader.Read();
            while (reader.TokenType != JsonToken.EndObject)
            {
                reader.Read();
            }
        }

        return l;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        //ToDo here we can decide to write the json as 
        //if only has one attribute output as string if it has more output as list
    }
}

И класс страны, что это то же самое, что и метод BuildCountry

[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class Country
{
    public int Id { get; set; }

    [JsonProperty(PropertyName = "name")]
    public string Name { get; set; }

    [JsonProperty(PropertyName = "isoCode")]
    public string IsoCode { get; set; }

    [JsonProperty(PropertyName = "dialCode")]
    public string DialCode { get; set; }

    internal static Country BuildCountry(dynamic expando)
    {
        return new Country
        {
            Id = expando.Id,
            Name = expando.name,
            IsoCode = expando.isoCode,
            DialCode = expando.dialCode
        };

    }
}
JavaScript Jobs — чат
JavaScript Jobs — чат
8 336 участник(ов)

JavaScript Jobs — чат для поиска работы и людей Правила оформления: https://teletype.in/@telegram-ru/r1WQe5F1m См. также: @mobile_jobs, @devops_jobs, @nodejs_jobs, @react_js, @angular_ru, @js_ru

JavaScript.ru
JavaScript.ru
7 932 участник(ов)

Сообщество сайта JavaScript.ru в Slack.

pro.js
pro.js
4 675 участник(ов)

Про JavaScript и NodeJS Invite: https://t.me/joinchat/Be4rsT5Rsgq30DHutjxXgA Правила: http://telegra.ph/ru-chat-rules-06-19 Вакансии только с ЗП, не чаще раза в неделю.

JavaScript — русскоговорящее сообщество
JavaScript — русскоговорящее сообщество
3 269 участник(ов)

Рекомендуем сразу отключить уведомления Правила: https://rudevs.network/ByaMH6un7 См. также: @js_noobs_ru, @nodejs_ru, @typescript_ru, @react_js, @electron_ru Вакансии и поиск работы: @javascript_jobs

DotNetRuChat
DotNetRuChat
2 992 участник(ов)

Чат русскоязычного .NET сообщества http://dotnet.ru/ Вам могут быть интересны: @dotnetchat, @cilchat, @fsharp_chat, @pro_net, @xamarin_russia, @microsoftstackjobs, @uwp_ru Флуд в @dotnettalks

JavaScript Noobs — сообщество новичков
JavaScript Noobs — сообщество новичков
2 484 участник(ов)

Чат для новичков

Microsoft Stack Jobs
Microsoft Stack Jobs
1 788 участник(ов)

Work & freelance only Microsoft Stack. Feed https://t.me/Microsoftstackjobsfeed Чат про F#: @Fsharp_chat Чат про C#: @CSharpChat Чат про Xamarin: @xamarin_russia Чат общения:@dotnettalks

javascript_ru
javascript_ru
915 участник(ов)

Сообщество любителей самого популярного языка программирования в мире. Чат основан в 2009 году. Логи: https://goo.gl/9EOeM7 Поддержка бота: @chat_linker (ссылка на репу внутри) Вам будут интересны @frontend_ru и @css_ru

pro.net
pro.net
710 участник(ов)

Обсуждение .NET Framework и всего, что с ним связано. Правила: не флудить не по теме, уважать ваших коллег и никакой рекламы (объявления о вакансиях можно согласовать с @AlexFails). Флудилка: @dotnettalks Участник @proDOT

jsChat
jsChat
603 участник(ов)

Чат посвященный программированию на языке javaScript Перед отправкой ссылки на Ваш контент посоветуйтесь с админом Все ссылки удаляются ботом автоматически

Microsoft Developer Community Chat
Microsoft Developer Community Chat
584 участник(ов)

Чат для разработчиков и системных администраторов Microsoft Developer Community. __________ Новостной канал: @msdevru __________ Баним за: оскорбления, мат, рекламу, флуд, флейм, спам, NSFW контент, а также большое количество оффтоп тем. @banofbot

JavaScript for Zombies Chat
JavaScript for Zombies Chat
492 участник(ов)

Чат про JavaScript для настоящих zombie! Вход строго по приглашениям! Ссылка для строгих приглашений: https://t.me/joinchat/AAMBHz3Uyr0tuZ7VaB029g

.NET Talks: Force Push Masters
.NET Talks: Force Push Masters
490 участник(ов)

Свободный чат .NET разработчиков. Правила: t.me/dotnettalks/56823 Вам могут быть интересны: @dotnetruchat, @dotnetchat, @cilchat, @fsharp_chat, @pro_net, @dotnetgroup, @xamarin_russia, @microsoftstackjobs, @uwp_ru http://combot.org/chat/-1001128250813

All That JS
All That JS
417 участник(ов)

JS на русском

.NET Chat Убежище
.NET Chat Убежище
246 участник(ов)

Чат .NET разработчиков под эгидой MSK/SPB .NET Community Group Вам могут быть интересны: @fsharp_chat, @dotnetruchat, @cilchat, @xamarin_russia, @microsoftstackjobs, @dotnetgroup Флуд в @dotnettalks

.NET CIL Chat
.NET CIL Chat
54 участник(ов)

.NET CIL (aka IL aka MSIL)