[英]Parsing json from external Api
我目前正在为外部REST API(我无法控制)编写ac#包装器库,该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<Country> GetCountries()
{
string endpointUrl = GenerateEndPointUri(...)
var countries = IssueApiGETRequest<CountriesWrapper>(endpointUrl);
return countries.Countries.Select(x =>
{
x.Value.Id = x.Key;
return x.Value;
}).ToList();
}
IssueAPIGetRequest
看起来像这样:
private T IssueApiGETRequest<T>(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<T>(json);
return result;
}
else
{
switch (response.StatusCode)
{
case HttpStatusCode.BadRequest:
throw new InvalidParameterException("Invalid parameters");
}
throw new Exception("Unable to process request");
}
}
}
}
这使我可以为外部API上的所有GET端点定义通用方法,并将它们序列化为自己定义的类型。
最后,我定义了以下Class实体:
[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; }
}
我对GetCountries方法不太满意,该方法必须重申反序列化返回的Dictionary并具有CountriesWrapper
类。
问题:我想知道我是否错过了一个窍门,或者有人可以建议一种更干净的方法来布置它。 同时保留向外部API发出GET请求的通用方法。
可以使用类似此答案的JsonConverter来完成
我认为json非常奇怪,无论如何,我实现了可以读取此类json的Converter。 我认为实施得不好,但您可以改善它
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
}
}
和国家/地区类一样,只是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
};
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.