Implementing global exception handling in an ASP.NET Core application

5 min


On the eve of the start of the course “C # ASP.NET Core Developer” prepared a traditional translation of useful material.

We also recommend watching a webinar on the topic “Differences in structural design patterns by examples”… In this open-ended lesson, participants and an expert instructor will explore three structural design patterns: Proxy, Adapter, and Decorator.


Introduction

Today in this article, we will discuss the concept of exception handling in ASP.NET Core applications. Exception handling is one of the most important imported functions or parts of any type of application that should always be carefully considered and implemented correctly. Exceptions are basically runtime-oriented error handling tools that occur during application execution. If this type of error is not handled properly, the application will stop as a result of their occurrence.

In ASP.NET Core, the concept of exception handling has undergone some changes and is now, so to speak, in much better shape for implementing exception handling. For any API project, implementing exception handling for each action will take a lot of time and extra effort. But we can implement a Global Exception handler that will catch all types of unhandled exceptions. The advantage of implementing a global exception handler is that we only need to define it in one place. Any exception thrown in our application will be handled through this handler, even if we declare new methods or controllers. So, in this article, we will discuss how to implement global exception handling in ASP.NET Core Web API.

Create an ASP.NET Core Web API Project in Visual Studio 2019

So, before we move on to discussing the global exception handler, we first need to create an ASP.NET Web API project. To do this, follow the steps given below.

  • Open Microsoft Visual Studio and click “Create a New Project”.

  • In the Create New Project dialog box, select ASP.NET Core Web Application for C # and click Next.

  • In the Configure your new project window, specify a name for the project and click the Create button.

  • In the Create a New ASP.NET Core Web Application dialog box, select API and click the Create button.

  • Make sure the check boxes for “Enable Docker Support” and “Configure for HTTPS” are cleared. We will not use these functions.

  • Make sure “No Authentication” is selected as we will not be using authentication either.

  • Click OK.

Using the UseExceptionHandler middleware in ASP.NET Core.

To implement a global exception handler, we can take advantage of ASP.NET Core’s built-in Middleware. Middleware is a software component embedded in the request processing pipeline that processes requests and responses in some way. We can use ASP.NET Core’s built-in middleware UseExceptionHandler as a global exception handler. The ASP.NET Core request processing pipeline includes a chain of middleware components. These components, in turn, contain a series of request delegates that are called one after the other. While incoming requests go through each of the middleware components in the pipeline, each of these components can either process the request or pass the request to the next component in the pipeline.

With this middleware, we can get all the detailed information about the exception object, such as stack trace, nested exception, message, etc., and also return this information through the API as output. We need to put the exception handling middleware in configure() file startup.cs… If we are using any MVC based application, we can use the exception handling middleware as shown below. This code snippet demonstrates how we can customize middleware UseExceptionHandler to redirect the user to an error page when any type of exception is thrown.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
{  
    app.UseExceptionHandler("/Home/Error");  
    app.UseMvc();  
} 

Now we need to check the exception message. To do this, open the file WeatherForecastController.cs and add the following action method to throw the exception:

[Route("GetExceptionInfo")]  
[HttpGet]  
public IEnumerable<string> GetExceptionInfo()  
{  
     string[] arrRetValues = null;  
     if (arrRetValues.Length > 0)  
     { }  
     return arrRetValues;  
} 

If we want to get detailed information about the exception objects like stack trace, message, etc., we can use the below code as the middleware of the exception –

app.UseExceptionHandler(  
                options =>  
                {  
                    options.Run(  
                        async context =>  
                        {  
                            context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;  
                            context.Response.ContentType = "text/html";  
                            var exceptionObject = context.Features.Get<IExceptionHandlerFeature>();  
                            if (null != exceptionObject)  
                            {  
                                var errorMessage = $"<b>Exception Error: {exceptionObject.Error.Message} </b> {exceptionObject.Error.StackTrace}";  
                                await context.Response.WriteAsync(errorMessage).ConfigureAwait(false);  
                            }  
                        });  
                }  
            );  

To check the output, simply run the API endpoint in any browser:

Defining Custom Middleware for Exception Handling in ASP.NET Core API

Alternatively, we can write our own middleware to handle any type of exception. In this section, we will demonstrate how to create a typical custom class middleware… Custom middleware also provides much more flexibility for exception handling. We can add a stack trace, an exception type name, an error code, or anything else that we want to include as part of the error message. The below code snippet shows a typical custom class middleware:

using Microsoft.AspNetCore.Http;    
using Newtonsoft.Json;    
using System;    
using System.Collections.Generic;    
using System.Linq;    
using System.Net;    
using System.Threading.Tasks;    
    
namespace API.DemoSample.Exceptions    
{    
    public class ExceptionHandlerMiddleware    
    {    
        private readonly RequestDelegate _next;    
    
        public ExceptionHandlerMiddleware(RequestDelegate next)    
        {    
            _next = next;    
        }    
    
        public async Task Invoke(HttpContext context)    
        {    
            try    
            {    
                await _next.Invoke(context);    
            }    
            catch (Exception ex)    
            {    
                    
            }    
        }    
    }    
} 

In the above class, the request delegate is passed to any middlewareMiddleware either processes it or passes it on to the next middleware in a chain. If the request is not successful, an exception will be thrown and then the method will be executed HandleExceptionMessageAsync in the block catch… So let’s update the method code Invokeas shown below:

public async Task Invoke(HttpContext context)  
{  
    try  
    {  
        await _next.Invoke(context);  
    }  
    catch (Exception ex)  
    {  
        await HandleExceptionMessageAsync(context, ex).ConfigureAwait(false);  
    }  
}  

Now we need to implement the method HandleExceptionMessageAsyncas shown below:

private static Task HandleExceptionMessageAsync(HttpContext context, Exception exception)  
{  
    context.Response.ContentType = "application/json";  
    int statusCode = (int)HttpStatusCode.InternalServerError;  
    var result = JsonConvert.SerializeObject(new  
    {  
        StatusCode = statusCode,  
        ErrorMessage = exception.Message  
    });  
    context.Response.ContentType = "application/json";  
    context.Response.StatusCode = statusCode;  
    return context.Response.WriteAsync(result);  
} 

Now, in the next step, we need to create a static class named ExceptionHandlerMiddlewareExtensions and add the below code to this class,

using Microsoft.AspNetCore.Builder;  
using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Threading.Tasks;  
  
namespace API.DemoSample.Exceptions  
{  
    public static class ExceptionHandlerMiddlewareExtensions  
    {  
        public static void UseExceptionHandlerMiddleware(this IApplicationBuilder app)  
        {  
            app.UseMiddleware<ExceptionHandlerMiddleware>();  
        }  
    }  
}  

In the last step, we need to enable our custom middleware in the Configure method of the startup class, as shown below:

app.UseExceptionHandlerMiddleware();  

Conclusion

Exception handling is essentially end-to-end functionality for any type of application. In this article, we discussed the process of implementing the concept of global exception handling. We can take advantage of global exception handling in any ASP.NET Core application to ensure that every exception is caught and returns the correct information associated with that exception. With global exception handling, we only need to write the exception handling code in one place for our entire application. Any suggestions, feedback or inquiries related to this article are greatly appreciated.


Learn more about the course “C # ASP.NET Core Developer”.

Watch the webinar on the topic “Differences in structural design patterns by examples.”


0 Comments

Leave a Reply