Reputation: 2174
I need to be able to deserialize in a correct type, and throw a random exception(type can be different) that comes as JSON from webApi. I tried doing it this way, but it comes up with error "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;
This is what my incoming JSON looks like:
{
"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
}
I need to be able to throw "InvalidLoginException"
Code edited Per Brian Roger's comments:
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;
}
}
Complete REST response:
{
"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
}
Upvotes: 1
Views: 2767
Reputation: 129697
You need to pass the exception type to DeserializeObject
. Otherwise it will deserialize to a JObject
, which obviously cannot be cast to an Exception
. Also, you do not need to create an instance of the Exception
first; that serves no purpose. Try it like this:
Type exType = Type.GetType(genericErrorResponse.ExceptionType, true);
Exception ex = (Exception)JsonConvert.DeserializeObject(expt, exType);
throw ex;
One other important note: your custom exception will need to have a constructor that accepts a SerializationInfo
and a StreamingContext
as shown below, otherwise it will not be able to be deserialized.
public class InvalidLoginException: Exception
{
public InvalidLoginException()
{
}
public InvalidLoginException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
Based on your edits, it looks like your JSON is somewhat variable and you are trying to deserialize it and reserialize it multiple times in order to figure out what you've actually got. Because of this variability, I would recommend deserializing into a JObject
first. This will make it easier to poke around without having to worry about matching it up to specific classes. Once you know what you have, you can use the ToObject()
method to convert the data part of the JSON into the target class. Here is how I would go about detecting the exception and then converting into an actual Exception
instance:
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);
}
}
Upvotes: 1