简体   繁体   English

无法读取来自 C# 中的 Web API 的 json

[英]Unable to read json comes from Web API in C#

Unable to read webapi value to a list object.无法将 webapi 值读取到列表对象。 Please see the screenshot value at the link http://prntscr.com/lcmw7q .请查看链接http://prntscr.com/lcmw7q 中的屏幕截图值。

Error is Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON object (eg {"name":"value"}) into type 'System.Collections.Generic.List`1[StudentProfileClient.StudentInfo]' because the type requires a JSON array (eg [1,2,3]) to deserialize correctly.错误是Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON object (eg {"name":"value"}) 到 type 'System.Collections.Generic.List`1[StudentProfileClient.StudentInfo]' 因为该类型需要一个JSON 数组(例如 [1,2,3])以正确反序列化。 To fix this error either change the JSON to a JSON array (eg [1,2,3]) or change the deserialized type so that it is a normal .NET type (eg not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object.要修复此错误,请将 JSON 更改为 JSON 数组(例如 [1,2,3])或更改反序列化类型,使其成为正常的 .NET 类型(例如,不是像整数这样的原始类型,而不是像这样的集合类型)可以从 JSON 对象反序列化的数组或列表)。 JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object. JsonObjectAttribute 也可以添加到类型中以强制它从 JSON 对象反序列化。 Path 'data', line 2, position 10.'路径“数据”,第 2 行,位置 10。

class StudentInfo
    {     




        public string cellPhone { get; set; }

        public string gender { get; set; }

        public string dateOfBirth { get; set; }
    }

 class RootClass
    {

        public int TotalCount { get; set; }
        public List<StudentInfo> stdinfo { get; set; }


    }
    static async Task GetData()
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("http://203.81.70.102:8092/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                HttpResponseMessage response;

                response = await client.GetAsync("control/qZkNkcGgWq6PiVbJzQ2=/student-profiles");

                if (response.IsSuccessStatusCode)
                {
                    List<StudentInfo> RootClass = new List<StudentInfo>();
                    RootClass = await response.Content.ReadAsAsync<List<StudentInfo>>();

                }

            }
        }

You can't directly deserialize from your API response using JsonConvert.DeserializeObject.您不能使用 JsonConvert.DeserializeObject 从 API 响应中直接反序列化。 ——

 JObject jsonResponse = JObject.Parse(jsonString);
    JObject objResponse = (JObject)jsonResponse["response"];
    Dictionary<string, JArray> _Data = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, JArray>>(objResponse.ToString());

Instead of declaring RootClass as List, use:不要将 RootClass 声明为 List,而是使用:

var RootClass = await response.Content.ReadAsAsync() var RootClass = 等待 response.Content.ReadAsAsync()

Put a breakpoint in the line, and check the Type that is returned from the API.在行中放置一个断点,并检查从 API 返回的类型 As var will accept anything, you can check the response.由于 var 将接受任何内容,您可以检查响应。 Basically your error says that you are trying to CAST to an invalid type, so the deserialization is not working properly.基本上,您的错误表明您正在尝试将 CAST 转换为无效类型,因此反序列化无法正常工作。

It seems the returning object is an array, maybe you need to get the array and convert it to a list, or even is a completly different object than the one you are expecting, have other properties, etc...似乎返回的对象是一个数组,也许您需要获取该数组并将其转换为列表,或者甚至是与您期望的对象完全不同的对象,具有其他属性等...

Best way to solve -> Debug, and make sure you are using the correct Type to deserialize解决的最佳方法 ->调试,并确保您使用正确的类型进行反序列化

1) By using JObject in Newtonsoft.json . 1) 通过在Newtonsoft.json使用JObject

Type below command in Package Manager Console.在包管理器控制台中键入以下命令。

Install-Package Newtonsoft.Json

if (response.IsSuccessStatusCode)
{
    string json = await response.Content.ReadAsStringAsync();

    JObject jObject = JObject.Parse(json);

    List<StudentInfo> studentInfos = jObject["data"].ToObject<List<StudentInfo>>();
}

Output:输出:

在此处输入图片说明


2) By without using Newtonsoft.json . 2) 不使用Newtonsoft.json

Type below command in Package Manager Console.在包管理器控制台中键入以下命令。

Install-Package Microsoft.AspNet.WebApi.Client

if (response.IsSuccessStatusCode)
{
    RootClass rootClass = await response.Content.ReadAsAsync<RootClass>();

    List<StudentInfo> studentInfos = rootClass.data;
}

Output:输出:

在此处输入图片说明

So your classes will be所以你的课程将是

public class StudentInfo
{
    public int sl { get; set; }
    public string studentId { get; set; }
    public string studentName { get; set; }
    public string school { get; set; }
    public string program { get; set; }
    public string fatherName { get; set; }
    public string motherName { get; set; }
    public string cellPhone { get; set; }
    public string gender { get; set; }
    public string dateOfBirth { get; set; }
}

public class RootClass
{
    public List<StudentInfo> data { get; set; }
    public string message { get; set; }
    public int total { get; set; }
}

simple solution, you need a wrapper简单的解决方案,你需要一个包装器

What does this look like in practice?这在实践中是什么样子的? It simply means that APIs that return lists of objects wrap the list in a top-level object.它只是意味着返回对象列表的 API 将列表包装在顶级对象中。 For example, suppose you have a Person data type in your API.例如,假设您的 API 中有一个 Person 数据类型。 If you GET a single Person, you might end up with the following JSON response:如果您 GET 一个 Person,您最终可能会得到以下 JSON 响应:

{ "name": "John Smith" }

All's well so far.到目前为止一切都很好。 But what if you want a list instead of a single one?但是如果你想要一个列表而不是一个列表呢? The most intuitive way might be as follows:最直观的方式可能如下:

[{"name": "John Smith"}, {"name": "Jane Smith"}]

But that's exactly the situation we need to avoid.但这正是我们需要避免的情况。 As a result we need to use a top-level object for lists such as this, with a single data property:因此,我们需要为这样的列表使用顶级对象,并具有单个数据属性:

{"data": [{"name": "John Smith"}, {"name": "Jane Smith"}]}

so.....所以.....

Class Students{
public List<StudentInfo> roots{get;set;}

}

keep your student class, add my class students, and deserialize to that;保留你的学生班级,添加我班级的学生,然后反序列化;

So you've got a class called RootClass.所以你有一个叫做 RootClass 的类。 And you've got a class called StudentInfo.您有一个名为 StudentInfo 的类。

Which one do you expect to get?你希望得到哪一个? Seems that you're getting something totally different.似乎你得到了完全不同的东西。 As I see here, https://prnt.sc/lcnlho , you should create a new class (or change RootClass structure) that will look like this正如我在这里看到的, https: //prnt.sc/lcnlho ,您应该创建一个新类(或更改 RootClass 结构),如下所示

 class ResponseContainer
    {
        public List<StudentInfo> data { get; set; }
    }

And instead of deserializing straight into List, you should deserialize to this ResponseContainer class:而不是直接反序列化到 List,你应该反序列化到这个 ResponseContainer 类:

var response = await response.Content.ReadAsAsync<ResponseContainer>();

ps If you want to use your RootClass, you should either rename the property stdinfo to "data", or add JsonProperty attribute like this: ps 如果你想使用你的 RootClass,你应该将属性 stdinfo 重命名为“data”,或者像这样添加 JsonProperty 属性:

 class RootClass
    {
        public int TotalCount { get; set; }

        [JsonProperty(PropertyName = "data")]
        public List<StudentInfo> stdinfo { get; set; }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM