6.0: Handling Errors in the API

Right now, if a user encounters an error we're handling that mainly by logging it to the console. When we're using Postman, we get a Developer Exception Page / "yellow screen of death." That's all well and good as we are developing because we know to have our console open checking for logged errors. However, that is obviously not a good user experience and exposes too much of our application to the user.

We also want to have control over what error messages the user received. We don't want to give them too much information about what went wrong. We also want to manage what they receive in the event of a username or password being entered incorrectly.

Adding Global Exception Handler

Currently, in the Configure() method of our Startup.cs class, we're telling the application to use the Developer Exception Page if we're in development mode.

Instead of doing that, we're just going to use the global exception handler for both modes.

In your Startup.cs class, remove this:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

And, in its place we'll configure a gloabl exception handler:

app.UseExceptionHandler(builder => {
    builder.Run(async context => {
        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

        var error = context.Features.Get<IExceptionHandlerFeature>();
        if (error != null)
        {
            await context.Response.WriteAsync(error.Error.Message);
        }
    });
});

Passing Errors into the Header as Application-Error

Now, let's add error information into the headers we send back when an error occurs. This will help our client application (Angular) deal with errors.

First, we need to import the metapackage to the .Helpers project in the .csproj file and click restore:

<ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.5" />
</ItemGroup>

In the Extensions.cs class in your Helpers project, add a new static extension method to the HttpResponse class called AddApplicationError():

public static void AddApplicationError(this HttpResponse response, string message)
{
    response.Headers.Add("Application-Error", message);
    response.Headers.Add("Access-Control-Expose-Origin-Headers", "Application-Error");
    response.Headers.Add("Access-Control-Allow-Origin", "*");
}

The first header adds our custom Application-Error header. The next two give it the permissions to do so. Without these - a browser will likely block it.

Next, we need to add this to our Configure() method where we built our exception handler:

app.UseExceptionHandler(builder => {
    builder.Run(async context => {
        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

        var error = context.Features.Get<IExceptionHandlerFeature>();
        if (error != null)
        {
            context.Response.AddApplicationError(error.Error.Message);          //  <--- Added
            await context.Response.WriteAsync(error.Error.Message);
        }
    });
});

Last updated