Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting response body on failed request with HttpRequestException

I am trying to log failed requests from my HttpRequestException.

My server returns error code and additional JSON payload at the response body. I need to access that JSON. How do I read the response body in case of an errored request? I know that the actual response is not null. It's an API and I confirm that it returns JSON payload with 4xx status codes, giving detailed insight about the error.

How do I access it? Here is my code:

using (var httpClient = new HttpClient())
{
    try
    {
        string resultString = await httpClient.GetStringAsync(endpoint);
        var result = JsonConvert.DeserializeObject<...>(resultString);
        return result;
    }
    catch (HttpRequestException ex)
    {
        throw ex;
    }
}

I am trying to get data in throw ex line, but I couldn't find a way.

like image 848
Can Poyrazoğlu Avatar asked Feb 23 '16 21:02

Can Poyrazoğlu


1 Answers

Exactly as @Frédéric suggested, if you use GetAsync method you'll get the proper HttpResponseMessage object which give more information about the response. To get details when error occurs you can desearlize the errors to an Exception or your custom exception object from Response content like below:

public static Exception CreateExceptionFromResponseErrors(HttpResponseMessage response)
{
    var httpErrorObject = response.Content.ReadAsStringAsync().Result;

    // Create an anonymous object to use as the template for deserialization:
    var anonymousErrorObject =
        new { message = "", ModelState = new Dictionary<string, string[]>() };

    // Deserialize:
    var deserializedErrorObject =
        JsonConvert.DeserializeAnonymousType(httpErrorObject, anonymousErrorObject);

    // Now wrap into an exception which best fullfills the needs of your application:
    var ex = new Exception();

    // Sometimes, there may be Model Errors:
    if (deserializedErrorObject.ModelState != null)
    {
        var errors =
            deserializedErrorObject.ModelState
                                    .Select(kvp => string.Join(". ", kvp.Value));
        for (int i = 0; i < errors.Count(); i++)
        {
            // Wrap the errors up into the base Exception.Data Dictionary:
            ex.Data.Add(i, errors.ElementAt(i));
        }
    }
    // Othertimes, there may not be Model Errors:
    else
    {
        var error =
            JsonConvert.DeserializeObject<Dictionary<string, string>>(httpErrorObject);
        foreach (var kvp in error)
        {
            // Wrap the errors up into the base Exception.Data Dictionary:
            ex.Data.Add(kvp.Key, kvp.Value);
        }
    }
    return ex;
}

Usage:

        using (var client = new HttpClient())
        {
            var response =
                await client.GetAsync("http://localhost:51137/api/Account/Register");


            if (!response.IsSuccessStatusCode)
            {
                // Unwrap the response and throw as an Api Exception:
                var ex = CreateExceptionFromResponseErrors(response);
                throw ex;
            }
        }

Here's the source article detailing more about handling the HttpResponseMessage and it's content.

like image 105
vendettamit Avatar answered Sep 20 '22 13:09

vendettamit