Search code examples
c#asp.net-web-apiexceptionhttpresponse

Correct use of EnsureSuccessStatusCode and IsSuccessStatusCode


I'm calling my Web API using an HttpClient and I see that there is an EnsureSuccessStatusCode method and an IsSuccessStatusCode property. Which one is appropriate?

I read this article and I have a few additional questions:

Usage of EnsureSuccessStatusCode and handling of HttpRequestException it throws

The issue I'm having is that if I send a GET request where I pass the ID of the object I want to retrieve, there are basically two outcomes:

  1. I get the object back with a status 200
  2. I could get null back because there was no match, however this results in a status of 404.

If I call EnsureSuccessStatusCode() a status 404 would result in an exception being thrown. That isn't ideal because when I was testing my code I kept getting a 404 error which at first made me think that the API URL was incorrect, but in reality there was no matching object with the supplied Id. In this case, I'd rather return a null object instead of throwing an exception.

So instead I tried checking the value of the IsSuccessfulStatusCode property. That seemed like a better choice and I can return a null object when this property is false, however, there are many status codes that can result in this property having a false value. 404 is one of them, but there are several other status codes, such as 400 Bad Request, 405 Method Not Allowed, etc. I'd like to log an exception for all unsuccessful error codes except for the 404's and I'm wondering if there is a better way to do this than inspecting the ResponseCode value of the response and then throwing an exception which gets caught by my catch block, which is where the logging takes place.

Here's the code for my GET method:

public static Customer GetCustomerByID(int id)
{
    try
        {
            using (var client = GetConfiguredClient())
            {
                Customer customer = null;
                var requestUri = $"Customers/{id}";

                using (var response = client.GetAsync(requestUri).Result)
                {
                    if (response.IsSuccessStatusCode)
                        customer = response.Content.ReadAsAsync<Customer>().Result;
                }

                return customer;
            }
        }
        catch (Exception ex)
        {
          ex.Data.Add(nameof(id), id);

          LogException(ex);

          throw;
        }
    }

This code will just return a null Customer if a non-successful status code is returned and nothing gets logged.

What is the best way to handle this situation?


Solution

  • Because of this:

    So instead I tried checking the value of the IsSuccessfulStatusCode property. That seemed like a better choice and I can return a null object when this property is false, however, there are many status codes that can result in this property having a false value. 404 is one of them, but there are several other status codes, such as 400 Bad Request, 405 Method Not Allowed, etc. I'd like to log an exception for all unsuccessful error codes except for the 404's and I'm wondering if there is a better way to do this than inspecting the ResponseCode value of the response and then throwing an exception which gets caught by my catch block, which is where the logging takes place.

    I would use the EnsureSuccessStatusCode method and then modify the catch block like below:

    public static Customer GetCustomerByID(int id)
    {
        try
        {
            using (var client = GetConfiguredClient())
            {
                var requestUri = $"Customers/{id}";
                Customer customer;
    
                using (var response = client.GetAsync(requestUri).Result)
                {
                    try 
                    {
                        response.EnsureSuccessStatusCode();
                        // If we reach here it means we can get the customer data.
                        customer = response.Content.ReadAsAsync<Customer>().Result;
                    }
                    catch(HttpRequestException)
                    {
                        if(response.StatusCode == HttpStatusCode.NotFound) // 404
                        {
                            customer = null;
                        }
                        else
                        {
                            throw;
                        }
                    }
                }
    
                return customer;
            }
        }
        catch (Exception ex)
        {
            ex.Data.Add(nameof(id), id);
    
            LogException(ex);
    
            throw;
        }
    }