【问题标题】:C# JSON Object wont deserializeC# JSON 对象不会反序列化
【发布时间】:2014-01-28 20:21:41
【问题描述】:

所以我已经能够为一些事情获取 JSON 对象,但是这个对象要复杂得多。

我正在尝试从 Reddit 获取 cmets。 这是我使用的方法:

    public async Task<List<string>> GetComments(string currentSubreddit, string topicID)
    {
        string commentUrl = "http://www.reddit.com/r/" + currentSubreddit  + "/comments/" + topicID + "/.json";
        List<Comments> commentList = new List<Comments>();
        string jsonText = await wc.GetJsonText(commentUrl);

        Comments.RootObject deserializeObject = Newtonsoft.Json.JsonConvert.DeserializeObject<Comments.RootObject>(jsonText);

        List<string> commentListTest = new List<string>();
        //List<string> commentListTest = deserializeObject.data.children[0].data.children;
        return commentListTest;

    }

这是 GetJsonText 方法:

    public async Task<string> GetJsonText(string url)
    {
        var request = WebRequest.Create(url);
        string text;
        request.ContentType = "application/json; charset=utf-8";
        var response = (HttpWebResponse)await request.GetResponseAsync();

        using (var sr = new StreamReader(response.GetResponseStream()))
        {
            text = sr.ReadToEnd();
        }

        return text;
    }

这里是对象的链接:http://pastebin.com/WQ8XXGNA 以及指向 jsonText 的链接:http://pastebin.com/7Kh6cA9a

返回的错误是这样的:

“Newtonsoft.Json.JsonSerializationException”类型的异常发生在 mscorlib.dll 中,但未在用户代码中处理

附加信息:无法将当前 JSON 数组(例如 [1,2,3])反序列化为类型 'JuicyReddit.Comments+RootObject',因为该类型需要 JSON 对象(例如 {"name":"value"})正确反序列化。

如果有人能帮助我找出问题所在,我将不胜感激。 谢谢

【问题讨论】:

  • 你从哪里得到这个 json 数据?认为您发布的 json 字符串无效。
  • @Jim 我得到这个 url 并在 GetJsonText www.reddit.com/r/AskReddit/cmets/1u​​t6xc/.json 中使用它
  • 这里解释了额外的错误stackoverflow.com/questions/17762032/…
  • @Jim 你知道如何在我使用 Newtonsoft 的情况下做到这一点吗?仍然不确定如何解决它。
  • 我为你添加了示例代码

标签: c# json windows visual-studio-2010 serialization


【解决方案1】:

实际上你的代码有一些问题

 public async Task<List<string>> GetComments(string currentSubreddit, string topicID)

这里你不需要返回一个字符串列表,你需要返回一个完整的对象

首先将模型中的 RootObject 重命名为适当的名称,例如“CommentsObject”

所以像这样设置你的类并将其命名为 CommentsObject.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace YOURNAMESPACE.Comments
{
    public class MediaEmbed
    {
    }

    public class SecureMediaEmbed
    {
    }

    public class Data4
    {
        public int count { get; set; }
        public string parent_id { get; set; }
        public List<string> children { get; set; }
        public string name { get; set; }
        public string id { get; set; }
        public string subreddit_id { get; set; }
        public object banned_by { get; set; }
        public string subreddit { get; set; }
        public object likes { get; set; }
        public object replies { get; set; }
        public bool? saved { get; set; }
        public int? gilded { get; set; }
        public string author { get; set; }
        public object approved_by { get; set; }
        public string body { get; set; }
        public object edited { get; set; }
        public object author_flair_css_class { get; set; }
        public int? downs { get; set; }
        public string body_html { get; set; }
        public string link_id { get; set; }
        public bool? score_hidden { get; set; }
        public double? created { get; set; }
        public object author_flair_text { get; set; }
        public double? created_utc { get; set; }
        public object distinguished { get; set; }
        public object num_reports { get; set; }
        public int? ups { get; set; }
    }

    public class Child2
    {
        public string kind { get; set; }
        public Data4 data { get; set; }
    }

    public class Data3
    {
        public string modhash { get; set; }
        public List<Child2> children { get; set; }
        public object after { get; set; }
        public object before { get; set; }
    }

    public class Replies
    {
        public string kind { get; set; }
        public Data3 data { get; set; }
    }

    public class Data2
    {
        public string domain { get; set; }
        public object banned_by { get; set; }
        public MediaEmbed media_embed { get; set; }
        public string subreddit { get; set; }
        public object selftext_html { get; set; }
        public string selftext { get; set; }
        public object likes { get; set; }
        public object secure_media { get; set; }
        public object link_flair_text { get; set; }
        public string id { get; set; }
        public SecureMediaEmbed secure_media_embed { get; set; }
        public bool clicked { get; set; }
        public bool stickied { get; set; }
        public string author { get; set; }
        public object media { get; set; }
        public int score { get; set; }
        public object approved_by { get; set; }
        public bool over_18 { get; set; }
        public bool hidden { get; set; }
        public string thumbnail { get; set; }
        public string subreddit_id { get; set; }
        public object edited { get; set; }
        public object link_flair_css_class { get; set; }
        public object author_flair_css_class { get; set; }
        public int downs { get; set; }
        public bool saved { get; set; }
        public bool is_self { get; set; }
        public string permalink { get; set; }
        public string name { get; set; }
        public double created { get; set; }
        public string url { get; set; }
        public object author_flair_text { get; set; }
        public string title { get; set; }
        public double created_utc { get; set; }
        public int ups { get; set; }
        public int num_comments { get; set; }
        public bool visited { get; set; }
        public object num_reports { get; set; }
        public object distinguished { get; set; }
        public Replies replies { get; set; }
        public int? gilded { get; set; }
        public string parent_id { get; set; }
        public string body { get; set; }
        public string body_html { get; set; }
        public string link_id { get; set; }
        public bool? score_hidden { get; set; }
        public int? count { get; set; }
        public List<string> children { get; set; }
    }

    public class Child
    {
        public string kind { get; set; }
        public Data2 data { get; set; }
    }

    public class Data
    {
        public string modhash { get; set; }
        public List<Child> children { get; set; }
        public object after { get; set; }
        public object before { get; set; }
    }

    public class CommentsObject
    {
        public string kind { get; set; }
        public Data data { get; set; }
    }
}

让你的命名空间正确!

然后处理请求并反序列化为commentobjects列表:(如果你愿意,你可以使用webclient而不是httpclient,这只是一个例子)

    private HttpClient client;

    public async Task<List<CommentsObject>> GetComments()
    {
        client = new HttpClient();
        var response = await client.GetAsync("http://www.reddit.com/r/AskReddit/comments/1ut6xc.json");
        if (response.IsSuccessStatusCode)
        {
            string json = await response.Content.ReadAsStringAsync();
            List<CommentsObject> comments = await JsonConvert.DeserializeObjectAsync<List<CommentsObject>>(json);
            return comments;
        }
        else
        {
            throw new Exception("Errorhandling message");
        }
    }

【讨论】:

  • 感谢您的深入回应,非常感谢。我带来的一个错误是命名空间。当我尝试为 GetComments() 方法执行 时,它说命名空间被用作类型
  • Getcmets() 是服务类或表单后端代码中的一种方法
  • 我明白了。这就是我的方法的类型: public async Task> GetComments(string url) 应该可以吗?因为我没有从中得到cmets。您介意开始聊天以获取快速帮助吗?
  • 实际上我认为我有它的工作。遍历此并将 cmets 添加到列表视图的最佳方法是什么?因为当我把列表拿回来时,里面总是有 2 个元素,我只是确定我应该做什么
  • 我想那将是一个不同的主题:),但是在这种情况下,你会得到 2 个数组,你需要深入挖掘并迭代以获得 cmets
【解决方案2】:

这并不理想(也不是完全的答案,而是更多的解决方法),但我创建了模拟 reddit 响应 json 的模型,以使反序列化超级容易。我在模型属性上使用 JsonProperty 属性来美化模型。

Here are the models

由于我的模型直接模拟了 json,我可以使用 json.net 的通用反序列化方法。

【讨论】:

  • 我将如何使用 Newtonsoft 插件。有点困惑它是如何工作的 S:
  • 假设我执行了对 reddit.com/r/all.json 的访问,Reddit 为您提供了一个“列表”。我用ListingModel 模拟了listing json。要获得强类型的ListingModel,我所要做的就是: var listing = JsonConvert.DeserializeObject(response) 其中 response 是 json。由于 ListingModel 及其子代模拟了返回的 json,它只是将 json 中的属性名称与我的模型匹配。如果您想了解它是如何使用的,请查看该 repo 中的测试控制台项目。
  • 感谢您的回复。我会看看你在说什么,并尝试让它发挥作用:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-05
相关资源
最近更新 更多