好的,我会尽量做到简短而具体。我从一个公共API获取一个JSON字符串,如下所示:(简短版本,只拍了2个样本)
[{
"$type": "Tfl.Api.Presentation.Entities.Line, Tfl.Api.Presentation.Entities",
"id": "bakerloo",
"name": "Bakerloo",
"modeName": "tube",
"disruptions": [],
"created": "2017-03-16T15:56:01.01Z",
"modified": "2017-03-16T15:56:01.01Z",
"lineStatuses": [
{
"$type": "Tfl.Api.Presentation.Entities.LineStatus, Tfl.Api.Presentation.Entities",
"id": 0,
"statusSeverity": 10,
"statusSeverityDescription": "Good Service",
"created": "0001-01-01T00:00:00",
"validityPeriods": []
}
],
"routeSections": [],
"serviceTypes": [
{
"$type": "Tfl.Api.Presentation.Entities.LineServiceTypeInfo, Tfl.Api.Presentation.Entities",
"name": "Regular",
"uri": "/Line/Route?ids=Bakerloo&serviceTypes=Regular"
}
],
"crowding": {
"$type": "Tfl.Api.Presentation.Entities.Crowding, Tfl.Api.Presentation.Entities"
}
},
{
"$type": "Tfl.Api.Presentation.Entities.Line, Tfl.Api.Presentation.Entities",
"id": "central",
"name": "Central",
"modeName": "tube",
"disruptions": [],
"created": "2017-03-16T15:56:01.01Z",
"modified": "2017-03-16T15:56:01.01Z",
"lineStatuses": [
{
"$type": "Tfl.Api.Presentation.Entities.LineStatus, Tfl.Api.Presentation.Entities",
"id": 0,
"statusSeverity": 10,
"statusSeverityDescription": "Good Service",
"created": "0001-01-01T00:00:00",
"validityPeriods": []
}
],
"routeSections": [],
"serviceTypes": [
{
"$type": "Tfl.Api.Presentation.Entities.LineServiceTypeInfo, Tfl.Api.Presentation.Entities",
"name": "Regular",
"uri": "/Line/Route?ids=Central&serviceTypes=Regular"
},
{
"$type": "Tfl.Api.Presentation.Entities.LineServiceTypeInfo, Tfl.Api.Presentation.Entities",
"name": "Night",
"uri": "/Line/Route?ids=Central&serviceTypes=Night"
}
],
"crowding": {
"$type": "Tfl.Api.Presentation.Entities.Crowding, Tfl.Api.Presentation.Entities"
}
}]
到目前为止一直很好,下面我将粘贴我正在使用的相关代码,并尝试将此JSON字符串反序列化为我从json2csharp免费在线服务获得的C#类。我试图实现此目的的相关代码是:
public async static Task<tubeStatusRootObject> GetTubeStatus(string url)
{
var http = new HttpClient();
var response = await http.GetAsync(url);
var result = await response.Content.ReadAsStringAsync(); //This is working
var deserializer = new DataContractJsonSerializer(typeof(tubeStatusRootObject));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (tubeStatusRootObject)deserializer.ReadObject(ms);
return data; //all "data" properties are null
}
你可以阅读上面的评论,所有我在返回之前获取内部数据都是空的。
json2csharp生成的类如下所示:
[DataContract]
public class Disruption
{
[DataMember]
public string type { get; set; }
[DataMember]
public string category { get; set; }
[DataMember]
public string categoryDescription { get; set; }
[DataMember]
public string description { get; set; }
[DataMember]
public string additionalInfo { get; set; }
[DataMember]
public string created { get; set; }
[DataMember]
public List<object> affectedRoutes { get; set; }
[DataMember]
public List<object> affectedStops { get; set; }
[DataMember]
public string closureText { get; set; }
[DataMember]
public bool? isWholeLine { get; set; }
}
[DataContract]
public class LineStatus
{
[DataMember]
public string type { get; set; }
[DataMember]
public int id { get; set; }
[DataMember]
public int statusSeverity { get; set; }
[DataMember]
public string statusSeverityDescription { get; set; }
[DataMember]
public string created { get; set; }
[DataMember]
public List<object> validityPeriods { get; set; }
[DataMember]
public string lineId { get; set; }
[DataMember]
public string reason { get; set; }
[DataMember]
public Disruption disruption { get; set; }
}
[DataContract]
public class ServiceType
{
[DataMember]
public string type { get; set; }
[DataMember]
public string name { get; set; }
[DataMember]
public string uri { get; set; }
}
[DataContract]
public class Crowding
{
[DataMember]
public string type { get; set; }
}
[DataContract]
public class tubeStatusRootObject
{
[DataMember]
public string type { get; set; }
[DataMember]
public string id { get; set; }
[DataMember]
public string name { get; set; }
[DataMember]
public string modeName { get; set; }
[DataMember]
public List<object> disruptions { get; set; }
[DataMember]
public string created { get; set; }
[DataMember]
public string modified { get; set; }
[DataMember]
public List<LineStatus> lineStatuses { get; set; }
[DataMember]
public List<object> routeSections { get; set; }
[DataMember]
public List<ServiceType> serviceTypes { get; set; }
[DataMember]
public Crowding crowding { get; set; }
}
显然我刚刚添加了[DataContract]
&{39}和[DataMember]
。任何人都知道我做错了什么,可以帮助我
我已按照Channel9
中的示例进行操作请不要标记重复,因为我发现了很多类似的问题,有些使用了newtonsoft json,但是我无法将解决方案实现到我的示例中
答案 0 :(得分:2)
提供的示例数据描述了一个数组(tubeStatusRootObject[])
但是当您尝试反序列化时,将其强制转换为单个实例,这是一个无效的强制转换。这就是data
为null
的原因。
如果有可用于解决问题的工具,也无需重新发明轮子。
static http = new HttpClient(); //reuse httpclient instead of creating a new one each time.
public async static Task<tubeStatusRootObject[]> GetTubeStatus(string url) {
var response = await http.GetAsync(url);
var json = await response.Content.ReadAsStringAsync(); //This is working
var data = Newtonsoft.Json.JsonConvert.DeserializeObject<tubeStatusRootObject[]>(json);
return data;
}
答案 1 :(得分:1)
这是一个有点复杂的对象。
当它反序列化时(你现在正在做的方式),它会查找与预期数据类型相同的对象的匹配名称。如果找不到,则反序列化失败并返回null。而且非常肯定。
如果不是newtonsoft,您可以将每个嵌套对象的数据类型与某些泛型对象匹配。或者需要执行一些字符串操作来自行反序列化(非常复杂)。
我更喜欢将Newtonsoft.json用于此类对象
答案 2 :(得分:1)
正如其他人所说的那样,你需要反序列化为一个数组,而不仅仅是你定义的一个类型的实例,因为响应是一个数组。
如果您将响应读入字符串,那么Json.Net意味着您只需要一个单行回复
var data= Newtonsoft.Json.JsonConvert.DeserializeObject<tubeStatusRootObject[]>(result);
使用DataContractJsonSerializer
时,将其与3 +行进行比较var deserializer = new DataContractJsonSerializer(typeof(tubeStatusRootObject[]));
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(result)))
{
var data = (tubeStatusRootObject[])deserializer.ReadObject(ms);
}
(注意使用using
包装器来确保释放MemoryStream。)
如果您直接将HTTP响应流读入解串器,则无法获得LoC保存。
using (var s = http.GetStreamAsync(url).Result)
using (var sr = new StreamReader(s))
using (var reader = new Newtonsoft.Json.JsonTextReader(sr))
{
var serializer = new Newtonsoft.Json.JsonSerializer();
var data = serializer.Deserialize<tubeStatusRootObject[]>(reader);
}
对战
using (var stream = await response.Content.ReadAsStreamAsync())
{
var dcjs = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(tubeStatusRootObject[]));
var data= (tubeStatusRootObject[])dcjs.ReadObject(stream);
}
您可能想要考虑的另一件事是性能。 Json.Net claim the following