Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从外部Api解析json_C#_Json_Json.net_Deserialization - Fatal编程技术网

C# 从外部Api解析json

C# 从外部Api解析json,c#,json,json.net,deserialization,C#,Json,Json.net,Deserialization,我目前正在为外部RESTAPI(我无法控制)编写一个c#包装器库,它返回JSON 要反序列化以下JSON { "countries": { "2": { "name": "Albania", "isoCode": "AL", "dialCode": "+355" }, "3": { "name": "Algeria", "

我目前正在为外部RESTAPI(我无法控制)编写一个c#包装器库,它返回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<Country> GetCountries()
{
  string endpointUrl = GenerateEndPointUri(...)

  var countries = IssueApiGETRequest<CountriesWrapper>(endpointUrl);

  return countries.Countries.Select(x =>
  {
    x.Value.Id = x.Key;
    return x.Value;
  }).ToList();
}
这允许我为外部API上的所有GET端点定义一个通用方法,并将它们序列化为我自己定义的类型

最后,我定义了这些类实体:

  [JsonObject(MemberSerialization = MemberSerialization.OptIn)]
  internal class CountriesWrapper
  {
    [JsonProperty(PropertyName = "countries")]
    public IDictionary<int, Country> 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; }
  }
[JsonObject(MemberSerialization=MemberSerialization.OptIn)]
内部类CountriesWrapper
{
[JsonProperty(PropertyName=“countries”)]
公共索引国家{get;set;}
}
[JsonObject(MemberSerialization=MemberSerialization.OptIn)]
公营国家
{
公共int Id{get;set;}
[JsonProperty(PropertyName=“name”)]
公共字符串名称{get;set;}
[JsonProperty(PropertyName=“isoCode”)]
公共字符串等位码{get;set;}
[JsonProperty(PropertyName=“dialCode”)]
公共字符串拨号代码{get;set;}
}
我对GetCountries方法不太满意,它必须在反序列化返回的字典上重复,并使用
CountriesWrapper


问题:我想知道我是否错过了一个技巧,或者是否有人可以建议一个更干净的方法来解决这个问题。同时保留向外部API发出GET请求的通用方法。

这可以通过类似的JsonConverter完成

我认为json非常奇怪,不管怎样,我实现了一个转换器,可以读取那种json。我认为它没有得到很好的实施,但你可以改进它

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var l = new List<Country>();
        dynamic expando = new ExpandoObject();
        var temp = expando as IDictionary<string, object>;
        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
    }
}
class CountriesConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(List<Country>));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var l = new List<Country>();
        dynamic expando = new ExpandoObject();
        var temp = expando as IDictionary<string, object>;
        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
    }
}
[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
        };

    }
}