2

An exception occurs in web service and ASP.NET Web API returns the exception in JSON response, like following:

HTTP/1.1 500 Internal Server Error
Content-Type: application/json; charset=utf-8

{ "Message":"An error has occurred.", 
  "ExceptionMessage":"Incorrect syntax near 'FooBar'.",
  "ExceptionType":"System.Data.SqlClient.SqlException", 
  "StackTrace":"at System.Web.Http.ApiController.blah.blah.blah" }

I would like to recreate the exception at client side. I want to convert the response to a SqlException object (in the example below) and then throw the exception. Some blogs have mentioned using Activator.CreateInstance() and Type.GetType() for creating an object in run-time with the type name in string and some have mentioned the use of dynamic. However, I am unable to figure how to use it properly. I would appreciate if someone can educate me. Thanks!

public class ExceptionResponse
{
    public string Message { get; set; }
    public string ExceptionType { get; set; }
    public string ExceptionMessage { get; set; }
    public string StackTrace { get; set; }
}

ExceptionResponse response = httpContent.ReadAsAsync<ExceptionResponse>().Result;
Type exceptionType = Type.GetType(response.ExceptionType);
throw Activator.CreateInstance(exceptionType, new object[]);

// Visual Studio indicates error: The type caught or throw must be derived from System.Exception
Tony
  • 1,827
  • 1
  • 22
  • 23

2 Answers2

0

As I understand, you try to handle an exception which reciving by http as a JSON-formatted message. So, you can try to serialize (parse) HTTP response and create a new instance of ExceptionResponse. For example:

using System.Web.Script.Serialization;

Your exception class will be like this:

public class ExceptionResponse : Exception {
    public string ExceptionType { get; set; }
    public string ExceptionMessage { get; set; }
}

Invoking:

var httpResponse = @"{ ""Message"":""An error has occurred."", ""ExceptionMessage"":""Incorrect syntax near 'FooBar'."", ""ExceptionType"":""System.Data.SqlClient.SqlException"",  ""StackTrace"":""at System.Web.Http.ApiController.blah.blah.blah"" }";

var e = new JavaScriptSerializer().Deserialize<ExceptionResponse>(httpResponse);
throw e;
  • How can I change variable e from type ExceptionResponse to type SqlException? In my program, I have a catch block to look for SqlException. – Tony Feb 15 '14 at 23:17
  • You can cast it explicitly. Because SqlException is a derived class from Exception. Try to check this: http://social.msdn.microsoft.com/Forums/vstudio/en-US/bdaeb0c6-1d9d-44c2-92c7-6cdda411a5e7/exception-casting-to-sqlexception?forum=csharpgeneral –  Feb 17 '14 at 05:23
  • 1
    The exception can be any type which is specified in the JSON response. It could be NotImplementedException or IOException for instance. How can I cast an object in run-time? – Tony Feb 17 '14 at 07:07
0

At last, I found an example from Github showing how to recreate a SQL exception using reflection.

public static class SqlExceptionCreator
{
    public static SqlException Create(string message, int errorCode)
    {
        SqlException exception = Instantiate<SqlException>();
        SetProperty(exception, "_message", message);

        var errors = new ArrayList();
        var errorCollection = Instantiate<SqlErrorCollection>();
        SetProperty(errorCollection, "errors", errors);

        var error = Instantiate<SqlError>();
        SetProperty(error, "number", errorCode);

        errors.Add(error);
        SetProperty(exception, "_errors", errorCollection);

        return exception;
    }


    private static T Instantiate<T>() where T : class
    {
        return System.Runtime.Serialization.FormatterServices.GetUninitializedObject(typeof(T)) as T;
    }

    private static void SetProperty<T>(T targetObject, string fieldName, object value)
    {
        var field = typeof(T).GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);
        if (field != null)
        {
            field.SetValue(targetObject, value);
        }
        else
        {
            throw new InvalidOperationException("No field with name " + fieldName);
        }
    }
}
Tony
  • 1,827
  • 1
  • 22
  • 23