Getting Web API Exception Details from a HttpResponseMessage

The Problem

It’s hard to get the details of an exception from a Web Api response when calling Web Api from a C# program. (Skip to the solution if you don’t care about the background), it even handle inner exceptions!

Some background

If you are working on a Web Api project and testing with a web browser you get a wonderful error page when an exception occurs. It gives you the message, exception message, exception type and the stack trace. Pretty much all you need to get started figuring out what has gone wrong.
Exception in browser

Same thing with fiddler, get a 500 back and you’ll even be treated to a Json version of the above.

Exception in fiddler

What about calling the action method from inside a c# program? Should be easy, you just create a client, setup the query, let it rip and examine the response for a success status and then read the content to get the returned values. Great, works fine.

What if the server threw an exception like the ones shown above, I thought it would be a simple thing to call response.Exception or the like and get all the details. But easy it is not.
I rooted around in the response for a while but found nothing that was simple to use.

The Solution

Instead I have added an extension method to HttpResponseMessage to parse the details of the exception from the Json in the response.Content.

using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;

namespace SimpleWebApiClient
{
    public static class HttpResponseMessageExtension
    {
        public static async Task<ExceptionResponse> ExceptionResponse(this HttpResponseMessage httpResponseMessage)
        {
            string responseContent = await httpResponseMessage.Content.ReadAsStringAsync();
            ExceptionResponse exceptionResponse = JsonConvert.DeserializeObject<ExceptionResponse>(responseContent);
            return exceptionResponse;
        }
    }

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

Usage is simple.

    //snip
    HttpResponseMessage response = await httpClient.GetAsync(query).ConfigureAwait(false);
    
    if (response.IsSuccessStatusCode)
        // return the value
    
    // But if an error occurred read the details           
    ExceptionResponse exceptionResponse = response.ExceptionResponse();

    //snip

 

Using JSON to store application preferences and configuration

Download full source code.

Storing configuration preferences in the database is not a hard task. It usually involves storing the name of the preference, the value and the type in the database. Then when retrieving the data you perform some sort of cast.

The casts tend to be a bit painful, but it works.

This is the call –

 
bool displayWidget = (bool) Convert.ChangeType(_preferenceManager.BadWayToCastToGetPreference("DisplayWidget"), typeof(bool));

And this is the called method –

 
        public object BadWayToCastToGetPreference<T>(string name)
        {
            var preference = Convert.ChangeType(_context.Preferences.SingleOrDefault(p => p.Name == name).Value, typeof(T));
            return preference;
        }

But this quickly falls apart when you want to store a list of something, this requires a custom way of generating a string that represents the list. A common way I’ve seen is to store the values as a pipe delimited list.

For example if you wanted to store three cities
Boston, New York and Seattle
they would become “Boston|New York|Seattle” when stored in the database.

Now you need a write code to turn that back into a list of strings.

The problem gets worse when you want to store some custom types, for example an emergency contact shaped like –

    public class EmergencyContact
    {
        public int Priority { get; set; }
        public string EmailAddress { get; set; }
    }

Or worse if you want to store a list of emergency contacts.

Rather than suffering all that pain, just use Json to serialize and deserialize the values. This makes life a lot easier.

I have a simple method to create the preference object that gets store in the database –

        private Preference CreatePreference(string name, string value, string type)
        {
            var preference = new Preference
            {
                Name = name,
                Value = value,
                Type = type,
                PreferenceID = Guid.NewGuid()
            };
            return preference;
        }

CreatePreference gets called like this for a simple string –

            string defaultEmail = "admin@example.com";
            Preference preference1 = CreatePreference("DefaultEmail", JsonConvert.SerializeObject(defaultEmail), defaultEmail.GetType().ToString());

And it’s the same when storing a more complex type.

            EmergencyContact[] secondaryEmergencyContacts = new[]
            {
                new EmergencyContact{ EmailAddress = "tom@example.com", Priority = 1},
                new EmergencyContact{ EmailAddress = "dick@example.com", Priority = 2},
                new EmergencyContact{ EmailAddress = "harry@example.com", Priority = 3},
            };
            Preference preference6 = CreatePreference("SecondaryEmergencyContacts",
                JsonConvert.SerializeObject(secondaryEmergencyContacts), secondaryEmergencyContacts.GetType().ToString());

To store these preferences in the database, its just simple Entity Framework.

            _context.Preferences.Add(preference1);
            _context.Preferences.Add(preference6);
            _context.SaveChanges();

And then to get the preferences back out of the database you call –

        public T GetPreference<T>(string name)
        {
            var preference =
                JsonConvert.DeserializeObject<T>(_context.Preferences.SingleOrDefault(p => p.Name == name).Value);
            return preference;
        }

Some might complain that it is slower than direct casts, and yes, it probably is. But if you haven’t measured it you shouldn’t optimize it. You can cache always cache preferences. And it is a lot neater than the alternative.

Download full source code.