【问题标题】:HttpClient parse JSON object to List, instead of JSON ArrayHttpClient 将 JSON 对象解析为 List,而不是 JSON Array
【发布时间】:2016-06-13 05:38:20
【问题描述】:

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

{"0":{"代码":"AL","Name":"ALBANIA"},"1":{"代码":"DZ","Name":"ALGERIA"},"2 ":{"代码":"AD","名称":"ANDORRA"},"3":{"代码":"AO","名称":"ANGOLA"},"4":{"代码" :"AI","名称":"ANGUILA"},"5":{"代码":"AG","名称":"ANTIGUA"},"6":{"代码":"AR","名称":"阿根廷"},"7":{"代码":"AM","名称":"亚美尼亚"},"8":{"代码":"AW","名称":"阿鲁巴" },"9":{"代码":"AU","名称":"澳大利亚"},"10":{"代码":"AT","名称":"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”类,都会引发以下异常:

“System.Net.Http.UnsupportedMediaTypeException”类型的异常 发生在 System.Net.Http.Formatting.dll 中但未在用户中处理 代码

附加信息:没有 MediaTypeFormatter 可用于读取 来自媒体类型为“text/html”的内容的“List`1”类型的对象。

如何在调用之前重新格式化响应,或将 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","名称":"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);
    }
}

【问题讨论】:

  • json2csharp.com 是一个工具,可以让你从 jsonresult 创建模型
  • @Eldho 它生成的模型很复杂,它为每个结果生成一个模型,如果数组返回 200 行,则每行生成 200 个类,一个用于容器:|
  • 在这种情况下尝试映射到字典对象

标签: c# json parsing httpclient json-deserialization


【解决方案1】:

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

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

查看聊天以了解更多信息。

【讨论】:

  • 不幸的是它不是一个restful服务,它只是一个普通的调用url和接收数据的服务,它使用查询字符串
  • 无论如何它应该可以工作。您仍然可以使用方法签名中使用参数提供的代码。
  • 这是我所做的:var client2 = new RestClient(); RestRequest req = new RestRequest(command); var executeAsGet = client2.Execute&lt;CityResponseVM&gt;(req).Data; 我尝试将command 传递给RestClientRestRequest,我还尝试同时使用CityVMCityResponseVM,所有这些其中返回null
  • 我已经更新了我的答案。我认为问题在于 JSON 格式。
  • 我建议你尝试反序列化为字典。
【解决方案2】:

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

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

然后,您只需将 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" 现在是您想要的可枚举集合。请注意,语法可能是错误的,因为我正在头脑中回复,但该过程是有效的,应该可以解决您的问题。

【讨论】:

  • 使用 CountryVMCountryResponseVM 甚至 CityResponseVMCityVM:附加信息:无法将当前 JSON 对象(例如 {"name":"value"})反序列化为类型'System.Collections.Generic.IEnumerable`1[Otrams.Controllers.CountryVM]' 因为该类型需要 JSON 数组(例如 [1,2,3])才能正确反序列化。
  • 另外,确保代码中的所有对象都是 [Serializable]。这很重要。
  • 它确实奏效了,但是根据smokednes 所说的,我对其进行了测试,它不需要可序列化的属性,顺便说一句,谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多