【问题标题】:Add JSON data to a generic collection将 JSON 数据添加到通用集合
【发布时间】:2015-09-28 14:13:26
【问题描述】:

至少在涉及到这样的事情时,我对 C# 还很陌生,所以对于我拥有的少量代码,我深表歉意。

我有一个名为 Project.cs 的类,需要使用它来保存我从 3rd 方 API 获得的数据对象。

这是课程:

//项目.cs

public sealed class Project
{
    public String Id { get; set; }
    public String Title { get; set; }
    public String Url { get; set; }
}

您在下面看到的方法应该是从 3rd 方 API 获取数据(JSON)。

此 API 以 JSON 形式返回项目列表。

幸运的是,我只需要从 API 中选择几个属性(Id、Title 和 URL)。

不幸的是,我不知道如何从 JSON 中挑选这些特定属性并将它们转换为 Project 类型的集合。

这是我目前所拥有的。我知道它很稀疏。

//ProjectSearch.cs

public IEnumerable<Project> GetProjects(String catId)
{
    //Get the data from the API
    WebRequest request = WebRequest.Create("http://research.a.edu/api/Catalogs('123')");
    request.ContentType = "application/json; charset=utf-8";
    WebResponse response = request.GetResponse();

    //put each object found in the API into a Project object        
    var project = new Project();

}

所以,现在,我被困住了。我不知道如何从 API 中获取所有对象并将它们放入 Project 类型的集合中。我需要一个循环吗?还是有其他的做法?

来自 API 的 JSON 示例:

{"odata.metadata":"http://research.a.edu/api/Catalogs/
$metadata#Catalogs /@Element", "odata.id":"http://research.a.edu/api/Catalogs
('123')",
"Id":"12345", "ParentID":"xxxx","Name":"Test1","Created":"1/1/2015","Modified":"2/1/2015","Deleted","0","URL":"http://yoursite/1",
('123')",
"Id":"7897", "ParentID":"xxxx","Name":"Test2","Created":"4/1/2015","Modified":"7/1/2015","Deleted","1","URL":"http://yoursite/2",
('123')",
"Id":"65335", "ParentID":"xxxx","Name":"Test3","Created":"7/1/2015","Modified":"9/1/2015","Deleted","0","URL":"http://yoursite/3"
}

我迷路了。

如果有人能告诉我,我将不胜感激。

谢谢!

【问题讨论】:

  • JSON 数据是什么样的?
  • 你在谷歌上搜索过 JSON 反序列化器吗?
  • 将JSON解析为代表完整数据的类还是解析为动态然后复制你需要的数据?
  • 你能添加一个json示例吗? @999cm999

标签: c# .net json c#-4.0


【解决方案1】:

您应该查看最流行的 .NET JSON 库:Newtonsoft JSON

使用非常简单。此示例取自网站:

string json = @"{
  'Name': 'Bad Boys',
  'ReleaseDate': '1995-4-7T00:00:00',
  'Genres': [
    'Action',
    'Comedy'
  ]
}";

Movie m = JsonConvert.DeserializeObject<Movie>(json);

string name = m.Name;

【讨论】:

  • 谢谢,这究竟是如何工作的?如果 JSON 中有超过 1 部电影怎么办?是否需要遍历 JSON 然后添加到 Movie 类?谢谢!
  • 数组也是可以接受的。如果不想使用序列化方式,也可以手动解析JSON,使用LINQ to JSON取数据。
  • 所以这一次只适用于一个对象?如果 JSON 包含 3 部电影,我必须执行 Movie m = JsonConvert... 3 次?谢谢
  • 不,那么您将拥有即JsonConvert.DeserializeObject&lt;Movie[]&gt;(json)
  • 哦,好的,这样就可以将 JSON 集合转换为 Movie 对象了?谢谢!
【解决方案2】:

我有两个实用程序函数,我只是为了这个目的而保留的(一个用于 GET,另一个用于 POST)。它使用泛型作为返回类型,因此可以“在任何地方”使用。

    public static T RetrieveContent<T>(string url)
    {
        if (String.IsNullOrWhiteSpace(url))
            throw new ArgumentNullException("url");

        T returnValue = default(T);

        try
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = "GET";
            request.ContentType = "application/x-www-form-urlencoded";
            request.Accept = "application/json; charset=utf-8";
            using (WebResponse response = request.GetResponse())
            {
                if (response != null)
                {
                    using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                    {
                        var serializer = new JsonSerializer();
                        var jsonTextReader = new JsonTextReader(reader);
                        returnValue = serializer.Deserialize<T>(jsonTextReader);
                    }
                }
            }
        }
        catch (Exception e)
        {
            string errMsg = String.Format("UtilitiesBL:RetrieveContent<T>(url). There was an error retrieving content from URL: {0}.", url);
            throw new Exception(errMsg, e);
        }

        return returnValue;

    }

    public static T RetrieveContentPost<T>(string url, string postData)
    {
        if (String.IsNullOrWhiteSpace(url))
            throw new ArgumentNullException("url");

        T returnValue = default(T);


        try
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            byte[] contentBytes = Encoding.UTF8.GetBytes(postData);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = contentBytes.Length;
            request.Accept = "application/json; charset=utf-8";

            // Get the request stream.
            using(Stream dataStream = request.GetRequestStream())
            {
                // Write the data to the request stream.
                dataStream.Write(contentBytes, 0, contentBytes.Length);
            }
            using (WebResponse response = request.GetResponse())
            {
                if (response != null)
                {
                    using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                    {
                        var serializer = new JsonSerializer();
                        var jsonTextReader = new JsonTextReader(reader);
                        returnValue = serializer.Deserialize<T>(jsonTextReader);
                    }

                }
            }
        }
        catch (Exception e)
        {
            string errMsg = String.Format("UtilitiesBL:RetrieveContentPost(url, postData). There was an error retrieving content from URL: {0}.", url);
            throw new Exception(errMsg, e);
        }

        return returnValue;

    }

使用问题中的示例,您的代码将如下所示:

public IEnumerable<Project> GetProjects(String catId)
{
    string url = String.Format("http://research.a.edu/api/Catalogs('{0}')", catId);
    return RetrieveContent<List<Project>>(url);
}

【讨论】:

  • 谢谢!要消化的东西太多了!如果我的 JSON 包含大量我不需要的数据,这将如何工作?我需要挑选出所有的对象,但每个对象只需要几个属性。
  • 我的荣幸。 serializer.Deserialize&lt;T&gt;(jsonTextReader) 将仅映射您的类中存在的属性并忽略其他属性。您希望我扩展代码的任何部分吗?
  • 谢谢。那么我是否只需将其复制并粘贴到我的公共 IEnumerable GetProjects(String catId) 方法中?
  • @999cm999:我添加了一些示例代码,展示了如何重组您的方法调用。
  • 谢谢,我真的很喜欢这个。很有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-30
  • 1970-01-01
  • 2012-06-29
  • 1970-01-01
相关资源
最近更新 更多