JSON 反序列化为正确类型的异常
JSON Exception deserializing into the proper type
我需要能够以正确的类型进行反序列化,并抛出来自 webApi 的 JSON 随机异常(类型可以不同)。我尝试这样做,但出现错误 "type caught or thrown must derive from system.exception"
//genericErrorResponse.ExceptionType = (string)"InvalidLoginException"
Type exType = Type.GetType(genericErrorResponse.ExceptionType);
object ex = Activator.CreateInstance(exType);
ex = JsonConvert.DeserializeObject(expt); //(string)exception JSON
throw ex;
这是我收到的 JSON 的样子:
{
"ClassName": "InvalidLoginException",
"Message": "Invalid User Name",
"Data": {},
"InnerException": null,
"HelpURL": null,
"StackTraceString": "....",
"RemoteStackTraceString": null,
"RemoteStackIndex": 0,
"ExceptionMethod": "....",
"HResult": -2147024809,
"Source": "DB",
"WatsonBuckets": null,
"ParamName": null
}
我需要能够投掷 "InvalidLoginException"
根据 Brian Roger 的评论编辑代码:
string httpContent = await httpResponse.Content.ReadAsStringAsync();
RestResponse<Object> genericResponse = JsonConvert.DeserializeObject<RestResponse<Object>>(httpContent);
if(genericResponse.Status.Code == 1074) {
RestErrorResponse<Exception> genericErrorResponse = JsonConvert.DeserializeObject<RestErrorResponse<Exception>>(httpContent);
if (genericErrorResponse.Exception != null)
{
Assembly ExAssembly = Assembly.Load("myExceptions");
Type exType = ExAssembly.GetType(genericErrorResponse.ExceptionType);
//this is where i probably loose data and unable to reconstruct it anymore
string expt = JsonConvert.SerializeObject(genericErrorResponse.Exception);
//but i cannot do SerializeObject(genericErrorResponse.Exception, exType)
//I Also cannot do JsonConvert.DeserializeObject<RestResponse<exType>>(httpContent)
//this will not deserealize it anymore
Exception ex = (Exception)JsonConvert.DeserializeObject(expt, exType);
throw ex;
}
}
完整的 REST 响应:
{
"Exception": {
"ClassName": "InvalidLoginException",
"Message": "Invalid User Name",
"Data": {},
"InnerException": null,
"HelpURL": null,
"StackTraceString": "....",
"RemoteStackTraceString": null,
"RemoteStackIndex": 0,
"ExceptionMethod": "....",
"HResult": -2147024809,
"Source": "DB",
"WatsonBuckets": null,
"ParamName": null
},
"Status": {
"Verbal": "Error",
"Code": 1074
},
"Content": null
}
您需要将异常类型传递给 DeserializeObject
。否则它将反序列化为 JObject
,这显然不能转换为 Exception
。另外,您不需要先创建 Exception
的实例;那没有用。像这样尝试:
Type exType = Type.GetType(genericErrorResponse.ExceptionType, true);
Exception ex = (Exception)JsonConvert.DeserializeObject(expt, exType);
throw ex;
另一个重要注意事项:您的自定义异常需要有一个接受 SerializationInfo
和 StreamingContext
的构造函数,如下所示,否则将无法反序列化。
public class InvalidLoginException: Exception
{
public InvalidLoginException()
{
}
public InvalidLoginException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
根据您的编辑,您的 JSON 似乎有些变化,您正试图对其进行反序列化和重新序列化多次,以便弄清楚您实际得到了什么。由于这种可变性,我建议首先反序列化为 JObject
。这将使四处寻找变得更容易,而不必担心将其与特定的 classes 匹配。一旦知道自己拥有什么,就可以使用 ToObject()
方法将 JSON 的数据部分转换为目标 class。以下是我将如何检测异常然后转换为实际的 Exception
实例:
string httpContent = await httpResponse.Content.ReadAsStringAsync();
JObject responseObject = JObject.Parse(httpContent);
int statusCode = (int)responseObject.SelectToken("Status.Code");
if (statusCode == 1074)
{
string exceptionClassName = (string)responseObject.SelectToken("Exception.ClassName");
Assembly exAssembly = Assembly.Load("myExceptions");
Type exType = exAssembly.GetType(exceptionClassName, false);
if (exType != null)
{
Exception ex = (Exception)responseObject["Exception"].ToObject(exType);
throw ex;
}
else
{
// exception class was not found, so just throw a generic one
string message = (string)responseObject.SelectToken("Exception.Message");
throw new Exception(message);
}
}
我需要能够以正确的类型进行反序列化,并抛出来自 webApi 的 JSON 随机异常(类型可以不同)。我尝试这样做,但出现错误 "type caught or thrown must derive from system.exception"
//genericErrorResponse.ExceptionType = (string)"InvalidLoginException"
Type exType = Type.GetType(genericErrorResponse.ExceptionType);
object ex = Activator.CreateInstance(exType);
ex = JsonConvert.DeserializeObject(expt); //(string)exception JSON
throw ex;
这是我收到的 JSON 的样子:
{
"ClassName": "InvalidLoginException",
"Message": "Invalid User Name",
"Data": {},
"InnerException": null,
"HelpURL": null,
"StackTraceString": "....",
"RemoteStackTraceString": null,
"RemoteStackIndex": 0,
"ExceptionMethod": "....",
"HResult": -2147024809,
"Source": "DB",
"WatsonBuckets": null,
"ParamName": null
}
我需要能够投掷 "InvalidLoginException"
根据 Brian Roger 的评论编辑代码:
string httpContent = await httpResponse.Content.ReadAsStringAsync();
RestResponse<Object> genericResponse = JsonConvert.DeserializeObject<RestResponse<Object>>(httpContent);
if(genericResponse.Status.Code == 1074) {
RestErrorResponse<Exception> genericErrorResponse = JsonConvert.DeserializeObject<RestErrorResponse<Exception>>(httpContent);
if (genericErrorResponse.Exception != null)
{
Assembly ExAssembly = Assembly.Load("myExceptions");
Type exType = ExAssembly.GetType(genericErrorResponse.ExceptionType);
//this is where i probably loose data and unable to reconstruct it anymore
string expt = JsonConvert.SerializeObject(genericErrorResponse.Exception);
//but i cannot do SerializeObject(genericErrorResponse.Exception, exType)
//I Also cannot do JsonConvert.DeserializeObject<RestResponse<exType>>(httpContent)
//this will not deserealize it anymore
Exception ex = (Exception)JsonConvert.DeserializeObject(expt, exType);
throw ex;
}
}
完整的 REST 响应:
{
"Exception": {
"ClassName": "InvalidLoginException",
"Message": "Invalid User Name",
"Data": {},
"InnerException": null,
"HelpURL": null,
"StackTraceString": "....",
"RemoteStackTraceString": null,
"RemoteStackIndex": 0,
"ExceptionMethod": "....",
"HResult": -2147024809,
"Source": "DB",
"WatsonBuckets": null,
"ParamName": null
},
"Status": {
"Verbal": "Error",
"Code": 1074
},
"Content": null
}
您需要将异常类型传递给 DeserializeObject
。否则它将反序列化为 JObject
,这显然不能转换为 Exception
。另外,您不需要先创建 Exception
的实例;那没有用。像这样尝试:
Type exType = Type.GetType(genericErrorResponse.ExceptionType, true);
Exception ex = (Exception)JsonConvert.DeserializeObject(expt, exType);
throw ex;
另一个重要注意事项:您的自定义异常需要有一个接受 SerializationInfo
和 StreamingContext
的构造函数,如下所示,否则将无法反序列化。
public class InvalidLoginException: Exception
{
public InvalidLoginException()
{
}
public InvalidLoginException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
根据您的编辑,您的 JSON 似乎有些变化,您正试图对其进行反序列化和重新序列化多次,以便弄清楚您实际得到了什么。由于这种可变性,我建议首先反序列化为 JObject
。这将使四处寻找变得更容易,而不必担心将其与特定的 classes 匹配。一旦知道自己拥有什么,就可以使用 ToObject()
方法将 JSON 的数据部分转换为目标 class。以下是我将如何检测异常然后转换为实际的 Exception
实例:
string httpContent = await httpResponse.Content.ReadAsStringAsync();
JObject responseObject = JObject.Parse(httpContent);
int statusCode = (int)responseObject.SelectToken("Status.Code");
if (statusCode == 1074)
{
string exceptionClassName = (string)responseObject.SelectToken("Exception.ClassName");
Assembly exAssembly = Assembly.Load("myExceptions");
Type exType = exAssembly.GetType(exceptionClassName, false);
if (exType != null)
{
Exception ex = (Exception)responseObject["Exception"].ToObject(exType);
throw ex;
}
else
{
// exception class was not found, so just throw a generic one
string message = (string)responseObject.SelectToken("Exception.Message");
throw new Exception(message);
}
}