我对使用C#和JSON数据相对较新,我正在寻求指导。我正在使用C#3.0,.NET3.5SP1和JSON.NET 3.5r6。
我有一个定义的C#类,我需要从JSON结构填充。但是,并非从Web服务检索的条目的每个JSON结构都包含在C#类中定义的所有可能的属性。
我一直在做一些看似错误的,艰难的方法,只是从JObject中逐一挑出每个值,并将字符串转换为所需的类属性。
JsonSerializer serializer = new JsonSerializer();
var o = (JObject)serializer.Deserialize(myjsondata);
MyAccount.EmployeeID = (string)o["employeeid"][0];
将JSON结构反序列化为C#类并处理来自JSON源的可能缺少数据的最佳方法是什么?
我的课程定义为:
public class MyAccount
{
[JsonProperty(PropertyName = "username")]
public string UserID { get; set; }
[JsonProperty(PropertyName = "givenname")]
public string GivenName { get; set; }
[JsonProperty(PropertyName = "sn")]
public string Surname { get; set; }
[JsonProperty(PropertyName = "passwordexpired")]
public DateTime PasswordExpire { get; set; }
[JsonProperty(PropertyName = "primaryaffiliation")]
public string PrimaryAffiliation { get; set; }
[JsonProperty(PropertyName = "affiliation")]
public string[] Affiliation { get; set; }
[JsonProperty(PropertyName = "affiliationstatus")]
public string AffiliationStatus { get; set; }
[JsonProperty(PropertyName = "affiliationmodifytimestamp")]
public DateTime AffiliationLastModified { get; set; }
[JsonProperty(PropertyName = "employeeid")]
public string EmployeeID { get; set; }
[JsonProperty(PropertyName = "accountstatus")]
public string AccountStatus { get; set; }
[JsonProperty(PropertyName = "accountstatusexpiration")]
public DateTime AccountStatusExpiration { get; set; }
[JsonProperty(PropertyName = "accountstatusexpmaxdate")]
public DateTime AccountStatusExpirationMaxDate { get; set; }
[JsonProperty(PropertyName = "accountstatusmodifytimestamp")]
public DateTime AccountStatusModified { get; set; }
[JsonProperty(PropertyName = "accountstatusexpnotice")]
public string AccountStatusExpNotice { get; set; }
[JsonProperty(PropertyName = "accountstatusmodifiedby")]
public Dictionary<DateTime, string> AccountStatusModifiedBy { get; set; }
[JsonProperty(PropertyName = "entrycreatedate")]
public DateTime EntryCreatedate { get; set; }
[JsonProperty(PropertyName = "entrydeactivationdate")]
public DateTime EntryDeactivationDate { get; set; }
}
要解析的JSON样本是:
{
"givenname": [
"Robert"
],
"passwordexpired": "20091031041550Z",
"accountstatus": [
"active"
],
"accountstatusexpiration": [
"20100612000000Z"
],
"accountstatusexpmaxdate": [
"20110410000000Z"
],
"accountstatusmodifiedby": {
"20100214173242Z": "tdecker",
"20100304003242Z": "jsmith",
"20100324103242Z": "jsmith",
"20100325000005Z": "rjones",
"20100326210634Z": "jsmith",
"20100326211130Z": "jsmith"
},
"accountstatusmodifytimestamp": [
"20100312001213Z"
],
"affiliation": [
"Employee",
"Contractor",
"Staff"
],
"affiliationmodifytimestamp": [
"20100312001213Z"
],
"affiliationstatus": [
"detached"
],
"entrycreatedate": [
"20000922072747Z"
],
"username": [
"rjohnson"
],
"primaryaffiliation": [
"Staff"
],
"employeeid": [
"999777666"
],
"sn": [
"Johnson"
]
}
答案 0 :(得分:270)
使用
var rootObject = JsonConvert.DeserializeObject<RootObject>(string json);
上创建课程
Json.NET文档: Serializing and Deserializing JSON with Json.NET
答案 1 :(得分:77)
您是否尝试过使用通用的DeserializeObject方法?
JsonConvert.DeserializeObject<MyAccount>(myjsondata);
JSON数据中任何缺少的字段都应该保留为NULL。
更新:
如果JSON字符串是数组,请尝试:
var jarray = JsonConvert.DeserializeObject<List<MyAccount>>(myjsondata);
jarray
应该是List<MyAccount>
。
另一个更新:
您获得的异常与对象数组不一致 - 我认为序列化程序在使用Dictionary类型accountstatusmodifiedby
属性时遇到问题。
尝试从序列化中排除accountstatusmodifiedby
属性,看看是否有帮助。如果是,您可能需要以不同的方式表示该属性。
答案 2 :(得分:49)
转载的答案
您可以使用C#dynamic
类型来简化操作。这种技术也使得重新分解更简单,因为它不依赖于魔术字符串。
<强>的Json 强>
下面的json
字符串是来自http api调用的简单响应,它定义了两个属性:Id
和Name
。
{"Id": 1, "Name": "biofractal"}
<强> C#强>
使用JsonConvert.DeserializeObject<dynamic>()
将此字符串反序列化为动态类型,然后以通常的方式访问其属性。
var results = JsonConvert.DeserializeObject<dynamic>(json);
var id = results.Id;
var name= results.Name;
注意:NewtonSoft程序集的NuGet链接为http://nuget.org/packages/newtonsoft.json。不要忘记添加:using Newtonsoft.Json;
来访问这些类。
答案 3 :(得分:8)
您可以使用:
JsonConvert.PopulateObject(json, obj);
这里:json
是json字符串,obj
是目标对象。请参阅:example
注意:PopulateObject()
不会删除obj的列表数据,Populate()
之后,obj's
列表成员将包含其原始数据和来自json字符串的数据
答案 4 :(得分:3)
建立bbant的答案,这是我从远程URL反序列化JSON的完整解决方案。
using Newtonsoft.Json;
using System.Net.Http;
namespace Base
{
public class ApiConsumer<T>
{
public T data;
private string url;
public CalendarApiConsumer(string url)
{
this.url = url;
this.data = getItems();
}
private T getItems()
{
T result = default(T);
HttpClient client = new HttpClient();
// This allows for debugging possible JSON issues
var settings = new JsonSerializerSettings
{
Error = (sender, args) =>
{
if (System.Diagnostics.Debugger.IsAttached)
{
System.Diagnostics.Debugger.Break();
}
}
};
using (HttpResponseMessage response = client.GetAsync(this.url).Result)
{
if (response.IsSuccessStatusCode)
{
result = JsonConvert.DeserializeObject<T>(response.Content.ReadAsStringAsync().Result, settings);
}
}
return result;
}
}
}
用法如下:
ApiConsumer<FeedResult> feed = new ApiConsumer<FeedResult>("http://example.info/feeds/feeds.aspx?alt=json-in-script");
FeedResult
是使用Xamasoft JSON Class Generator
以下是我使用的设置的屏幕截图,允许web version无法解释的奇怪的属性名称。
答案 5 :(得分:1)
您可以尝试在线查看某些类生成器以获取更多信息。但是,我相信一些答案是有用的。这是我的方法可能有用。
以下代码是在考虑动态方法的情况下制作的。
dynObj = (JArray)JsonConvert.DeserializeObject(nvm);
foreach (JObject item in dynObj)
{
foreach (JObject trend in item["trends"])
{
Console.WriteLine("{0}-{1}-{2}", trend["query"], trend["name"], trend["url"]);
}
}
此代码基本上允许您访问Json字符串中包含的成员。只是一种不同的方式而不需要课程。 query
,trend
和url
是Json字符串中包含的对象。
您也可以使用this website。不要相信100%的课程,但你明白了。
答案 6 :(得分:1)
我发现我的错误构建了我的对象。我使用http://json2csharp.com/从JSON生成我的对象类。一旦我有了正确的Oject,我就可以毫无问题地进行投射。诺比特,诺布错了。以为我会添加它以防你有同样的问题。
答案 7 :(得分:0)
假设您的示例数据正确,您的给定名称和括在括号中的其他条目是JS中的数组...您将希望对这些数据类型使用List。并列出了例如accountstatusexpmaxdate ...我认为你的例子的日期格式不正确,所以不确定你的例子中哪些不正确。
这是一篇旧帖子,但想要记下这些问题。