Status Code with empty response in ASP.NET Core

If you create JSON APIs, you know that sometimes it is useful to return empty response with just status code set. For example when user calls the API to get a document with id 123 and he doesn’t have the rights to this particular document, it is a good practice to return with a status ‘403 Forbidden’. When you do that, you don’t need to add anything to the response - status code is just enough.

My previous project was build with NancyFx, which makes it trivial:

Get["/products/{id}"] = parameters =>;
{
    Product item = repository.Get(parameters.id);
    if (item == null)
    {
        return HttpStatusCode.NotFound;
    }
    return item;
};

In the ASP.NET 4.6 you had an option to throw a special exception which had a field for response status code:

public Product GetProduct(int id)
{
    Product item = repository.Get(id);
    if (item == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }
    return item;
}

Right now I am working on an API built with the new ASP.NET Core and I wanted to do the same. It quickly turned out there is no HttpResponseException class there anymore. There were basically two simple options:

  1. Change controller method signature to return IActionResult **and return **StatusCode(403) - I didn’t like it as I want to have proper type returned from my controller methods</li>
  2. Set the Response.StatusCode manually and return null (or 0 if the method returns int) - also didn’t like it as you can’t easily unit test it.</li>

After some googling and searching on StackOverflow, I found a nice solution for this problem - to create a new type of exception: HttpStatusCodeException, containing a field for the status code and a middleware, which will catch these exceptions and reformat the response to just contain the status code.

This is the code for both things:

public class ErrorHandlerMiddleware
{
    public class HttpStatusCodeException : Exception
    {
        public HttpStatusCode StatusCode { get; set; }

        public HttpStatusCodeException(HttpStatusCode statusCode)
        {
            StatusCode = statusCode;
        }
    }

    private readonly RequestDelegate _next;

    public ErrorHandlerMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (HttpStatusCodeException exception)
        {
            context.Response.StatusCode = (int) exception.StatusCode;
            context.Response.Headers.Clear();
        }
    }
}

As you can see, the HttpStatusCodeException takes standard HttpStatusCode as a constructor parameter and then it is read and returned by the middleware in the catch statement.

I like this solution because it’s very simple and elegant. I don’t return any content (even null) from the API methods and have proper type checking in the controller methods.

Comments

Michał Dymel's Picture

About Michał Dymel

Passionate software developer interested in Web Development, .NET, Angular2, Architecture and security. Currently doing remote consulting.

Szczecin, Poland https://devblog.dymel.pl
Web Analytics