反序列化 Json Web API 响应 - 嵌套对象
Deserialize Json Web API Response - Nested objects
我正在通过 SSIS 脚本组件收到 Web API JSON 响应,返回格式如下:
{
"Success": true,
"Response": {
"Applications": [
{
"App_ID": 1638486,
"App_Ref": "Test Example",
"Status": "Complete",
"Error_Code": null,
"Error_Message": null,
"Create_Dt": "2014-05-14 03:09:01.030 +00:00",
"Modify_Dt": "2014-05-14 03:10:59.757 +00:00",
"Client_Name": "Silver Chef",
"Client_Code": "SLVC01",
"Centrelink_Status": "Receiving_Logons"
},
{
"App_ID": 1637906,
"App_Ref": "SME Demo",
"Status": "Complete",
"Error_Code": null,
"Error_Message": null,
"Create_Dt": "2015-10-08 03:07:26.793 +00:00",
"Modify_Dt": "2015-10-08 03:23:32.833 +00:00",
"Client_Name": "Silver Chef",
"Client_Code": "SLVC01",
"Centrelink_Status": "Receiving_Logons"
},
{
"App_ID": 1585286,
"App_Ref": "Test",
"Status": "Receiving_Logons",
"Error_Code": null,
"Error_Message": null,
"Create_Dt": "2015-12-04 03:12:49.617 +00:00",
"Modify_Dt": "2015-12-04 03:12:49.617 +00:00",
"Client_Name": "Silver Chef",
"Client_Code": "SLVC01",
"Centrelink_Status": "Receiving_Logons"
}
],
"Current_Dt": "2016-11-11 01:01:01.743 +00:00",
"Last_App_Dt": "2016-10-03 22:48:56.397 +00:00",
"Count": 500,
"Total": 1870
}
}
我已声明以下内容类:
public class Application
{
public int App_ID { get; set; }
public string App_Ref { get; set; }
public string Status { get; set; }
public int Error_Code { get; set; }
public string Error_Message { get; set; }
public DateTime Create_Dt { get; set; }
public DateTime Modify_Dt { get; set; }
public string Client_Name { get; set; }
public string Client_Code { get; set; }
public int Centrelink_Status { get; set; }
}
public class Response
{
public List<Application> Applications { get; set; }
public string Current_Dt { get; set; }
public string Last_App_Dt { get; set; }
public int Count { get; set; }
public int Total { get; set; }
}
public class RootObject
{
public bool Success { get; set; }
public Response Response { get; set; }
}
And this is the method that I am using to get the response.
private RootObject GetWebServiceResult(string vAPIUrl)
{
string vAPIToken = Variables.APIToken;
//Create Web Request
HttpWebRequest apireq = (HttpWebRequest)WebRequest.Create(vAPIUrl);
apireq.ContentType = "application/json";
apireq.Method = "POST";
string jsonPostStr = "{\"Settings\": {\"API_Token\": \"" + vAPIToken + "\"}, \"Payload\": {}}";
byte[] postString = Encoding.UTF8.GetBytes(jsonPostStr);
apireq.ContentLength = postString.Length;
Stream jsonStream = apireq.GetRequestStream();
jsonStream.Write(postString, 0, postString.Length);
jsonStream.Close();
// Get Web Response
HttpWebResponse apirsp = (HttpWebResponse)apireq.GetResponse();
RootObject jsonResponse = null;
Stream jsonRspStream = apirsp.GetResponseStream();
string apiResponseString = null;
using (StreamReader reader = new StreamReader(jsonRspStream))
{
apiResponseString = reader.ReadToEnd();
Console.WriteLine(apiResponseString);
reader.Close();
}
JavaScriptSerializer returnJson = new JavaScriptSerializer();
//var serialJsonStr = returnJson.Serialize(apiResponseString);
System.Windows.Forms.MessageBox.Show(apiResponseString);
jsonResponse = returnJson.Deserialize<RootObject>(apiResponseString);
return jsonResponse;
}
我的问题是 returnJson.Deserialize(apiResponseString); 似乎 return null 并随后导致失败。
我错过了什么?我想我在这个阶段有点代码盲。
提前致谢
Application
class 有几个问题:
您已将 Application.Error_Code
定义为整数:
public int Error_Code { get; set; }
但实际上,在JSON中,它有一个空值:
"Error_Code": null,
因此 Error_Code
需要是引用类型 (string
) 或可空值类型 (int?
),具体取决于它在非空时所持有的内容。
您已将 Centrelink_Status
定义为 int
,但在 JSON 中它是一个字符串:
"Centrelink_Status": "Receiving_Logons"
因此它也需要是数据模型中的字符串。
因此您的 Application
class 应该如下所示:
public class Application
{
public int App_ID { get; set; }
public string App_Ref { get; set; }
public string Status { get; set; }
public int? Error_Code { get; set; } // Or string, if not numeric
public string Error_Message { get; set; }
public DateTime Create_Dt { get; set; }
public DateTime Modify_Dt { get; set; }
public string Client_Name { get; set; }
public string Client_Code { get; set; }
public string Centrelink_Status { get; set; }
}
如果 JSON.
中有可能出现 null
值,您可能还希望使这些 DateTime
属性可为空
顺便说一下,当我试图反序列化这个 JSON 时,我抛出了一个异常,而不是返回的空值:
System.InvalidOperationException was unhandled
Message="Cannot convert null to a value type."
Source="System.Web.Extensions"
StackTrace:
在您的实际代码中,您是否捕获并吞噬了异常?这是一个坏主意,因为它往往会隐藏这样的错误。至少,在调试时你应该在抛出任何异常时中断,包括第一次机会异常 - 即使这是 不是 默认行为。请参阅 Managing Exceptions with the Debugger. If you find there are certain types of exception that are frequently thrown and are irrelevant to debugging, you can selectively re-ignore them. Had you done so this bug would have been more straightforward to track down. Admittedly, the error is not very explanatory, but it does give a hint. If you were to use json.net 反序列化您的 JSON,错误消息会更清楚:
Newtonsoft.Json.JsonSerializationException occurred
Message="Error converting value {null} to type 'System.Int32'. Path 'Response.Applications[0].Error_Code', line 9, position 26."
Source="Newtonsoft.Json"
StackTrace:
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType) in C:\Development\Releases\Json\Working\Newtonsoft.Json\Working-Signed\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:line 986
InnerException: System.InvalidCastException
Message="Null object cannot be converted to a value type."
Source="mscorlib"
StackTrace:
at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType) in C:\Development\Releases\Json\Working\Newtonsoft.Json\Working-Signed\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:line 979
InnerException:
我正在通过 SSIS 脚本组件收到 Web API JSON 响应,返回格式如下:
{
"Success": true,
"Response": {
"Applications": [
{
"App_ID": 1638486,
"App_Ref": "Test Example",
"Status": "Complete",
"Error_Code": null,
"Error_Message": null,
"Create_Dt": "2014-05-14 03:09:01.030 +00:00",
"Modify_Dt": "2014-05-14 03:10:59.757 +00:00",
"Client_Name": "Silver Chef",
"Client_Code": "SLVC01",
"Centrelink_Status": "Receiving_Logons"
},
{
"App_ID": 1637906,
"App_Ref": "SME Demo",
"Status": "Complete",
"Error_Code": null,
"Error_Message": null,
"Create_Dt": "2015-10-08 03:07:26.793 +00:00",
"Modify_Dt": "2015-10-08 03:23:32.833 +00:00",
"Client_Name": "Silver Chef",
"Client_Code": "SLVC01",
"Centrelink_Status": "Receiving_Logons"
},
{
"App_ID": 1585286,
"App_Ref": "Test",
"Status": "Receiving_Logons",
"Error_Code": null,
"Error_Message": null,
"Create_Dt": "2015-12-04 03:12:49.617 +00:00",
"Modify_Dt": "2015-12-04 03:12:49.617 +00:00",
"Client_Name": "Silver Chef",
"Client_Code": "SLVC01",
"Centrelink_Status": "Receiving_Logons"
}
],
"Current_Dt": "2016-11-11 01:01:01.743 +00:00",
"Last_App_Dt": "2016-10-03 22:48:56.397 +00:00",
"Count": 500,
"Total": 1870
}
}
我已声明以下内容类:
public class Application
{
public int App_ID { get; set; }
public string App_Ref { get; set; }
public string Status { get; set; }
public int Error_Code { get; set; }
public string Error_Message { get; set; }
public DateTime Create_Dt { get; set; }
public DateTime Modify_Dt { get; set; }
public string Client_Name { get; set; }
public string Client_Code { get; set; }
public int Centrelink_Status { get; set; }
}
public class Response
{
public List<Application> Applications { get; set; }
public string Current_Dt { get; set; }
public string Last_App_Dt { get; set; }
public int Count { get; set; }
public int Total { get; set; }
}
public class RootObject
{
public bool Success { get; set; }
public Response Response { get; set; }
}
And this is the method that I am using to get the response.
private RootObject GetWebServiceResult(string vAPIUrl)
{
string vAPIToken = Variables.APIToken;
//Create Web Request
HttpWebRequest apireq = (HttpWebRequest)WebRequest.Create(vAPIUrl);
apireq.ContentType = "application/json";
apireq.Method = "POST";
string jsonPostStr = "{\"Settings\": {\"API_Token\": \"" + vAPIToken + "\"}, \"Payload\": {}}";
byte[] postString = Encoding.UTF8.GetBytes(jsonPostStr);
apireq.ContentLength = postString.Length;
Stream jsonStream = apireq.GetRequestStream();
jsonStream.Write(postString, 0, postString.Length);
jsonStream.Close();
// Get Web Response
HttpWebResponse apirsp = (HttpWebResponse)apireq.GetResponse();
RootObject jsonResponse = null;
Stream jsonRspStream = apirsp.GetResponseStream();
string apiResponseString = null;
using (StreamReader reader = new StreamReader(jsonRspStream))
{
apiResponseString = reader.ReadToEnd();
Console.WriteLine(apiResponseString);
reader.Close();
}
JavaScriptSerializer returnJson = new JavaScriptSerializer();
//var serialJsonStr = returnJson.Serialize(apiResponseString);
System.Windows.Forms.MessageBox.Show(apiResponseString);
jsonResponse = returnJson.Deserialize<RootObject>(apiResponseString);
return jsonResponse;
}
我的问题是 returnJson.Deserialize(apiResponseString); 似乎 return null 并随后导致失败。
我错过了什么?我想我在这个阶段有点代码盲。
提前致谢
Application
class 有几个问题:
您已将
Application.Error_Code
定义为整数:public int Error_Code { get; set; }
但实际上,在JSON中,它有一个空值:
"Error_Code": null,
因此
Error_Code
需要是引用类型 (string
) 或可空值类型 (int?
),具体取决于它在非空时所持有的内容。您已将
Centrelink_Status
定义为int
,但在 JSON 中它是一个字符串:"Centrelink_Status": "Receiving_Logons"
因此它也需要是数据模型中的字符串。
因此您的 Application
class 应该如下所示:
public class Application
{
public int App_ID { get; set; }
public string App_Ref { get; set; }
public string Status { get; set; }
public int? Error_Code { get; set; } // Or string, if not numeric
public string Error_Message { get; set; }
public DateTime Create_Dt { get; set; }
public DateTime Modify_Dt { get; set; }
public string Client_Name { get; set; }
public string Client_Code { get; set; }
public string Centrelink_Status { get; set; }
}
如果 JSON.
中有可能出现null
值,您可能还希望使这些 DateTime
属性可为空
顺便说一下,当我试图反序列化这个 JSON 时,我抛出了一个异常,而不是返回的空值:
System.InvalidOperationException was unhandled
Message="Cannot convert null to a value type."
Source="System.Web.Extensions"
StackTrace:
在您的实际代码中,您是否捕获并吞噬了异常?这是一个坏主意,因为它往往会隐藏这样的错误。至少,在调试时你应该在抛出任何异常时中断,包括第一次机会异常 - 即使这是 不是 默认行为。请参阅 Managing Exceptions with the Debugger. If you find there are certain types of exception that are frequently thrown and are irrelevant to debugging, you can selectively re-ignore them. Had you done so this bug would have been more straightforward to track down. Admittedly, the error is not very explanatory, but it does give a hint. If you were to use json.net 反序列化您的 JSON,错误消息会更清楚:
Newtonsoft.Json.JsonSerializationException occurred
Message="Error converting value {null} to type 'System.Int32'. Path 'Response.Applications[0].Error_Code', line 9, position 26."
Source="Newtonsoft.Json"
StackTrace:
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType) in C:\Development\Releases\Json\Working\Newtonsoft.Json\Working-Signed\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:line 986
InnerException: System.InvalidCastException
Message="Null object cannot be converted to a value type."
Source="mscorlib"
StackTrace:
at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType) in C:\Development\Releases\Json\Working\Newtonsoft.Json\Working-Signed\Src\Newtonsoft.Json\Serialization\JsonSerializerInternalReader.cs:line 979
InnerException: