HttpClient 将 JSON 对象解析为列表,而不是 JSON 数组

HttpClient parse JSON object to List, instead of JSON Array

我们的一位客户需要一些数据,这些数据应该从服务提供商处获得。该服务是用 PHP 编写的,比 soap 或 wcf 服务更像一个网络 api,响应格式如下:

{"0":{"Code":"AL","Name":"ALBANIA"},"1":{"Code":"DZ","Name":"ALGERIA"},"2":{"Code":"AD","Name":"ANDORRA"},"3":{"Code":"AO","Name":"ANGOLA"},"4":{"Code":"AI","Name":"ANGUILLA"},"5":{"Code":"AG","Name":"ANTIGUA"},"6":{"Code":"AR","Name":"ARGENTINA"},"7":{"Code":"AM","Name":"ARMENIA"},"8":{"Code":"AW","Name":"ARUBA"},"9":{"Code":"AU","Name":"AUSTRALIA"},"10":{"Code":"AT","Name":"AUSTRIA"},"11":{"Code":"AZ","Name":"AZERBAIJAN"},"12":{"Code":"BS","Name":"BAHAMAS"},"StartTime":"2016-06-13 04:57:15","EndTime":"2016-06-13 04:57:15"}

如您所见,它是一个数组,但采用对象格式,这就是我遇到问题的原因。

我用的是HttpClient,我的模型是这样的:

public class CountryVM
{
    public string Code { get; set; }

    public string Name { get; set; }
}

我还对其进行了扩展,使其成为以下模型的一部分:

public class CountryResponseVM
{
    public List<CountryVM> CountryVMs { get; set; }
    public string StartTime { get; set; }
    public string EndTime { get; set; }
}

当我运行以下代码时:

using (var client = new HttpClient())
{
    var response = client.PostAsync(command, new StringContent(string.Empty)).Result;
    if (response.IsSuccessStatusCode)
    {
        List<CountryVM> readAsAsync = response.Content.ReadAsAsync<List<CountryVM>>().Result;
    }
}

无论是 'CountryVM' 还是 'CountryResponseVM' class,它都会抛出以下异常:

An exception of type 'System.Net.Http.UnsupportedMediaTypeException' occurred in System.Net.Http.Formatting.dll but was not handled in user code

Additional information: No MediaTypeFormatter is available to read an object of type 'List`1' from content with media type 'text/html'.

如何重新格式化响应,或者在调用之前将 json 对象解析为数组 ReadAsAsync 方法。


更新

我还有一个模型,在国家下面列出的城市。 城市模型似乎更正确,它有数组而不是对象,并给数组命名,但在所有情况下我仍然有与国家相同的问题。

回复:

{"CityInfo":[{"CityCode":"TIA-","Name":"Albania"},{"CityCode":"TIA-7","Name":"Berat"},{"CityCode":"TIA-3","Name":"Durres"},{"CityCode":"TIA-4","Name":"Korce"},{"CityCode":"TIA-8","Name":"Pogradec"},{"CityCode":"TIA-2","Name":"Sarande"},{"CityCode":"TIA-6","Name":"Shkoder"},{"CityCode":"TIA-1","Name":"Tirana"},{"CityCode":"TIA-5","Name":"Vlore"}],"StartTime":"2016-06-13 06:03:34","EndTime":"2016-06-13 06:03:34"}

型号:

public class CityResponseVM
{
    public List<CityVM> CityInfo { get; set; }
    public string StartTime { get; set; }
    public string EndTime { get; set; }
}

public class CityVM
{
    public string CityCode { get; set; }
    public string Name { get; set; }
}

并请求:

string command = Otrams.Url+Otrams.GetAction(ServiceAction.CityList) +"&username="+Otrams.Username+"&password="+Otrams.Password+"&gzip=no&country=AL";
using (var client = new HttpClient())
{
    var response = client.PostAsync(command, new StringContent(string.Empty)).Result;
    if (response.IsSuccessStatusCode)
    {
        //CityResponseVM readAsAsync = response.Content.ReadAsAsync<CityResponseVM>().Result;
        var rawData = response.Content.ReadAsStringAsync().Result;
        var myList = JsonConvert.DeserializeObject<IEnumerable<CityVM>>(rawData);
    }
}

从 NuGet 中获取 NewtonSoft.JSON 并将其与您的项目一起安装。然后进行以下操作:

用 [Serializable] 或 [DataContract] 属性标记您的 CountryVM class(我总是忘记哪个在哪个位置)

然后,您只需将 Response.Content 转换为 JSON,并将其序列化:

var rawData = Response.Content.ReadAll(); // forgot the proper syntax, just get the content as string

var myList = JsonConvert.DeserializeObject<IEnumerable<CountryVM>>(rawData);

"myList" 现在是一个你想要的可枚举集合。请注意,语法可能是错误的,因为我是在脑海中回复,但该过程是有效的,应该可以解决您的问题。

使用两个对象,一个用于反序列化,一个实际包含结果。

public class MyTempModel
{
    public DateTime StartTime { get; set; }
    public DateTime EndTime { get; set; }
    [JsonExtensionData]
    public Dictionary<string, object> Countries { get; set; }
}

public class MyRealModel : Dictionary<int, CountryVM>
{
    public DateTime? StartTime { get; set; }
    public DateTime? EndTime { get; set; }
}

反序列化:

var myList = JsonConvert.DeserializeObject<MyTempModel>(jsonResult);

var model = new MyRealModel
{
    StartTime = myList.StartTime,
    EndTime = myList.EndTime
};

foreach (var temp in myList.Countries)
{
    // Deserialize the actual ContryVm.
    var obj = JsonConvert.DeserializeObject<CountryVM>(temp.Value.ToString());
    int key = 0;
    int.TryParse(temp.Key, out key);
    model.Add(key, obj);
}

这里的关键部分是使用 JsonExtensionData,如这里所建议的:How to serialize a Dictionary as part of its parent object using Json.Net。它将启用字典格式,具有额外的属性,例如 StartTimeEndTime.

更高级的解决方案是使用 JsonConverter.

查看聊天了解更多信息。