【问题标题】:Parsing Dynamic Json datastructure to object C# / dotnet core将动态 Json 数据结构解析为对象 C#/dotnet 核心
【发布时间】:2017-05-07 10:34:45
【问题描述】:

我正在尝试将 Riot API 中的数据解析为 C# 对象 https://developer.riotgames.com/api-methods/#lol-static-data-v1.2/GET_getChampionList

        HttpClient client = new HttpClient();
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        HttpResponseMessage response = await client.GetAsync("https://global.api.riotgames.com/api/lol/static-data/EUW/v1.2/champion?champData=allytips%2Cenemytips%2Cimage%2Ctags&dataById=true&api_key=###################");

        if (response.IsSuccessStatusCode)
        {
            var streamTask = response.Content.ReadAsStreamAsync();
            var stringJson = await response.Content.ReadAsStringAsync();
            var serializer = new DataContractJsonSerializer(typeof(ChampionWrapper));
            var champions = serializer.ReadObject(await streamTask) as ChampionWrapper;
        }

到目前为止,我只转换了类型和版本。
数据结构如下:

{
  "type": "champion",
  "version": "7.9.1",
  "data": {
    "89": {
      "id": 89,
      "key": "Leona",
      "name": "Leona",
      "title": "the Radiant Dawn",
      "image": {
        "full": "Leona.png",
        "sprite": "champion2.png",
        "group": "champion",
        "x": 0,
        "y": 0,
        "w": 48,
        "h": 48
      },
      "allytips": [
        "Lead the charge and mark your foes with Sunlight before your allies deal damage.",
        "Shield of Daybreak and Zenith Blade form a powerful offensive combo.",
        "You can absorb a huge amount of damage using Eclipse, but you must stay near enemies to gain the bonus duration."
      ],
      "enemytips": [
        "When Leona activates Eclipse, you have three seconds to get away from her before she deals damage.",
        "Only foes in the center of Solar Flare get stunned, so you can often avoid this if you're quick."
      ],
      "tags": [
        "Tank",
        "Support"
      ]
    },
    "110": {
      "id": 110,
      "key": "Varus",
      "name": "Varus",
      "title": "the Arrow of Retribution",
      "image": {
        "full": "Varus.png",
        "sprite": "champion3.png",
        "group": "champion",
        "x": 336,
        "y": 96,
        "w": 48,
        "h": 48
      },

到目前为止,我有一个 ChampionWrapper:

public class ChampionWrapper
{
    public string type { get; set; }
    public string version { get; set; }
    public List<ChampionData> data { get; set; }

    public ChampionWrapper()
    {

    }
}

List ChampionData 未填充。版本和类型有效。

    public List<string> id {get;set;}
    public List<Champion> id { get; set; }
    public ChampionData()
    {

    }

这是冠军对象

    public string Id { get; set; }
    public string Name { get; set; }
    public string Title { get; set; }
    public List<string> AllyTips { get; set; }
    public List<string> EnemyTips { get; set; }
    public List<string> Tags { get; set; }

    public Champion()
    {

    }

我的主要问题是动态数据结构

"data": {
    "89": { .... }
    "110": { .... }

数字只是冠军的ID。

【问题讨论】:

    标签: c# json .net-core


    【解决方案1】:

    找到解决方案:

                DataContractJsonSerializerSettings settings = new DataContractJsonSerializerSettings();
                settings.UseSimpleDictionaryFormat = true;
    

    整件事:

            HttpClient client = new HttpClient();
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            HttpResponseMessage response = await client.GetAsync("https://global.api.riotgames.com/api/lol/static-data/EUW/v1.2/champion?champData=allytips%2Cenemytips%2Cimage%2Ctags&dataById=true&api_key=###########");
    
            if (response.IsSuccessStatusCode)
            {
                DataContractJsonSerializerSettings settings = new DataContractJsonSerializerSettings();
                settings.UseSimpleDictionaryFormat = true;
    
                var streamTask = response.Content.ReadAsStreamAsync();
                var stringJson = await response.Content.ReadAsStringAsync();
                var serializer = new DataContractJsonSerializer(typeof(ChampionWrapper), settings);
                var champions = serializer.ReadObject(await streamTask) as ChampionWrapper;
            }
    

    当然还有将列表更改为字典:

    public class ChampionWrapper
    {
        public string type { get; set; }
        public string version { get; set; }
        public Dictionary<string, Champion> data { get; set; }
    }
    

    【讨论】:

      【解决方案2】:

      您没有使用正确的类来反序列化您的对象。 json 中的data 属性不是List,而是更像Dictionary

      public class ChampionWrapper
      {
          public string type { get; set; }
          public string version { get; set; }
          public Dictionary<string, Champion> data { get; set; }
      }
      

      [编辑]

      我相信您使反序列化来自 Json 的响应的方式复杂化,而不是使用 DataContractSerializer 手动反序列化响应,您应该使用 ReadAsAsync&lt;T&gt; 扩展方法来获取您的类的对象:

      if(response.IsSuccessStatusCode)
      {
          var champions = await response.Content.ReadAsAsync<ChampionWrapper>();
      }
      

      这个扩展方法在Microsoft.AspNet.WebApi.Client nuget package里面找到,使用前记得添加。

      【讨论】:

      • 嗨。即使更改为 Dictionary 仍然无法正常工作
      • @Kiksen 更新了答案,包括反序列化您的回复的更好方法
      • -> 我找到了这个。问题是我使用的是 DotNetCore,它不支持 ReadAsAsync。
      猜你喜欢
      • 2012-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多