Application diagnostics
.NET .NET Core ASP.NET Core Best Practices C# Diagnostics Visual Studio Web API

An Overview of Error and Status Handling of HTTP Requests in a .NET Core Web API Application

Welcome to today’s post.

In today’s post I will provide an overview of the most common types of responses returned from a HTTP request to a .NET Core Web API and how to deal with them. I will look at an example and discuss some recommended practices on how to deal with them. I will also refer to some of my previous posts on the approaches I took on dealing with them.

The most common response we get from an HTTP request is the 200 (OK) response. This occurs when the request is successfully executed, and the response returns a status of 200. The client application would wrap the HTTP request into an exception block if the response status code was in error.

ActionResult Responses from ASP.NET Core Controllers

The HTTP response is of type ActionResult, which is defined as a type within ASP.NET Core and available as a response from an API controller.

An example of an API method that returns a successful or successful response is shown below:

[HttpPost("api/[controller]/Create")]
public async Task<ActionResult> Create([FromBody] BookViewModel model)
{
    if (ModelState.IsValid)
    {
        try
        {
            string sTitle = model.Title; 
            …
            string sLocation = model.Location; 

            BookViewModel book = new BookViewModel()
            {
                Title = sTitle,
                …
                Location = sLocation,
            };

            await _bookService.SaveBook(book);
            return Ok(book); 
        }
        catch (Exception ex)
        {
            _logger.LogError(ex.Message);
            return BadRequest("Cannot create book record.");
        }
    }
    else
        return BadRequest("Cannot create book record: Invalid properties.");
}

When the response obtained from an HTTP request is in error, the status code is above 400.

A common response is the Bad Request, which has a status code of 400. In addition to the status code, we can return a more meaningful message within the JSON response.

We can return a response like this:

return BadRequest("Cannot create book record.");

Inside of an exception block we could return the full error message from the exception:

catch (Exception ex)
{
    return BadRequest(ex.Message);
}

This might give the end user more detailed information to provide to support, however it is not considered best practice, in fact it is not considered to be OWASP compliant in terms of security.

I will explain why in the next section.

How much Error Detail do we return in API Responses?

What if the error message contained sensitive information, such as the name of a database, username, file paths etc. Such information would be useful for an intruder to conduct exploitation of the backend systems.

The response below, with the error message written to an application file log is more secure and provides less details to the end user than what is required.

catch (Exception ex)
{
    _logger.LogError(ex.Message);
    return BadRequest("Cannot create book record.");
}

What we have done is to balance the need to provide enough details to support staff to be able to handle the issue, and just enough detail to the end user to know there is an error and be able to report the issue back to the support team, who can follow up with 2nd or 3rd level support and inspect the backend file logs to more technical details.

Unhandled Server Errors

Where possible, an API should cover all cases of error handling and responses. Another type of error we can experience is the Internal Server Error, which has a status code of 500. In this case, the error root cause is non-programmatic and is related to a dependent service that the API is dependent on. These dependencies can include:

  • Database server Instance availability.
  • Internet Web Server App Pool availability.
  • Network resource availability.
  • External network availability.

Where availability of a resource is limited, the issue of timeouts is common, and this can result in different 500.xxx errors. In this case, more troubleshooting of the underlying cause will reveal the cause. Additional logging diagnostics is beneficial within the application configuration within the application start up can narrow what resources are causing the exception.

With unhandled errors that occur from within ASP.NET Core web applications, one suggestion is to use the UseExceptionHandler() middleware within the Configure() method in the start-up. Details of the exception handler approach for ASP.NET Core Web Razor UI applications are in my previous post, and I have discussed the exception handler approach with logging for ASP.NET Core Web API applications in another previous post.

Another common error type is based on application security. The Unauthorised error, which has a status code of 401 is caused by a security authentication scheme of the API. In this case, the request would not have been able to execute the API method due to a requirement for a valid user token to be passed into the request Authorization header. An example of an API method that is secured is shown below:

[HttpGet("api/[controller]/List")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public async Task<List<BookViewModel>> List()
{ 
    …
}

With errors that are dependent on declarative security, the error response is returned by default from the security middleware. With security errors related to authentication, the error returned is a 401 error (unauthorized). With security errors related to authorization, the error returned is a 403 error (forbidden). The 403 error is returned if an authenticated user context cannot be authorized access within an authorization handler.

in another one of my previous posts, I explain the details on how we use declarative claims based security authorization. I also explained the details on how use can use security authentication. Once the security middleware is setup correctly within our ASP.NET Core Web API or Web Application, the common 401 and 403 errors that we could experience when initially setting up security will be resolved.

The above overview should be sufficient to process the various types of errors within an ASP.NET Core application.

That is all for today’s post.

I hope you found this post useful and informative.

Social media & sharing icons powered by UltimatelySocial