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;

另一个重要注意事项:您的自定义异常需要有一个接受 SerializationInfoStreamingContext 的构造函数,如下所示,否则将无法反序列化。

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);
    }
}