-
Notifications
You must be signed in to change notification settings - Fork 0
Global Exception Handler
Exception handling is one of the most important part of any application that needs to addressed and implemented properly. Exceptions are mainly means for the run time errors which occur during the execution time of the application. So, if this type of error is not properly handled, then the application will be terminated.
The Global Exception Handler is a type of workflow designed to determine the project’s behavior when encountering an execution error. The benefit of implementing global exception handling is that you need to implement in at one place. Any exception occurs in your application will be handled, even when you add new controllers or new methods.
Custom Global Exception Handling Middleware is a piece of code that can be configured as a middleware in the ASP.NET Core pipeline which contains our custom error handling logics. There are a variety of exceptions that can be caught by this pipeline. This when configured in the Configure method of the Program class adds a middleware to the pipeline of the application that will catch any exceptions in and out of the application.
So, we need to configure UseCustomExceptionHandler inside configure() of Program.cs file.
app.UseCustomExceptionHandler();
Now create a MiddlewareExtensions file inside the Middlerware folder of API to add this middleware to the application pipeline as below,
public static class MiddlewareExtensions
{
public static IApplicationBuilder UseCustomExceptionHandler(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ExceptionHandlerMiddleware>();
}
}
Create a class Response inside Responses folder of Application to send uniform responses no matter what kind of requests it gets hit with. This make the work easier for whoever is consuming the API.
public class Response<T>
{
public Response()
{
}
public Response(T data, string message = null)
{
Succeeded = true;
Message = message;
Data = data;
}
public Response(string message)
{
Succeeded = false;
Message = message;
}
public bool Succeeded { get; set; }
public string Message { get; set; }
public List<string> Errors { get; set; }
public T Data { get; set; }
}
The Response class is of a generic type, meaning any kind of data can be passed along with it. Data property will hold the actual data returned from the server. Message contains any Exceptions or Info message in string type. And finally there is a boolean that denotes if the request is a success.
As mentioned earlier, let’s also create a Global Exception Handling Middleware. Create a new class and name it ExceptionHandlerMiddleware.cs inside the Middleware folder of API as below,
public class ExceptionHandlerMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger _logger;
public ExceptionHandlerMiddleware(RequestDelegate next ,ILogger<ExceptionHandlerMiddleware> logger)
{
_next = next; _logger = logger;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
_logger.LogError(ex, "", null);
await ConvertException(context, ex);
}
}
private Task ConvertException(HttpContext context, Exception exception)
{
HttpStatusCode httpStatusCode = HttpStatusCode.InternalServerError;
context.Response.ContentType = "application/json";
var result = string.Empty;
switch (exception)
{
case ValidationException validationException:
httpStatusCode = HttpStatusCode.BadRequest;
result = GetErrorMessages(validationException.ValdationErrors);
break;
case BadRequestException badRequestException:
httpStatusCode = HttpStatusCode.BadRequest;
result = GetErrorMessage(badRequestException.Message);
break;
case NotFoundException notFoundException:
httpStatusCode = HttpStatusCode.NotFound;
result = GetErrorMessage(notFoundException.Message);
break;
case ApplicationException appexception:
httpStatusCode = HttpStatusCode.BadRequest;
result = GetErrorMessage(appexception.Message);
break;
case Exception ex:
httpStatusCode = HttpStatusCode.BadRequest;
result = GetErrorMessage("Internal server error occurred contact dev team.");
break;
}
context.Response.StatusCode = (int)httpStatusCode;
return context.Response.WriteAsync(result);
}
private string GetErrorMessage(string message)
{
var response = new Response<string>();
response.Succeeded = false;
response.Errors = new List<string>();
response.Errors.Add(message);
return JsonConvert.SerializeObject(response);
}
private string GetErrorMessages(List<string> messages)
{
var response = new Response<string>();
response.Succeeded = false;
response.Errors = new List<string>();
response.Errors= messages;
return JsonConvert.SerializeObject(response);
}
}
With that done, let’s run the application and throw the case Exception exception in the Get method of the default controller and see how the error get’s displayed on Swagger.