How to implement global exception handling in .NET Core
Introduction of Global Exception
We often come up with exceptions in our application and we have two ways in general to handle those exception.
- Handle at controller/service level everywhere in application
- Handle from one place and control the application
Those approaches are fine and work well , I would like to talk about second one today
Pros and Cons of Global Exception Let’s see pros and cons of this approach
Pro (s) :
-
Code becomes easy to manage because we don’t need to look into n different try-catch blocks , just look from one place and deal them.
-
More readable because a few lines of code managing the whole exceptions of application
-
Removes repeated code (try-catch everywhere)
-
It gives us more control so we can catch exceptions and return response of our own type , in most cases we return Internal Server Error. Additionally it is a good approach to log those exceptions (Check my post on How to add logs via NLog or my friend Milan post on Logging with Serilog in .NET Core)
Con(s) :
- A global exception handler can make it harder because sometime it will catch the exception at broad level and deal with it accordingly without digging down to exact lower-level exception
If you are on short time and you need to implement exception handling then global exception handling is the best solution.
How to Implement it via Middleware
We have different ways to implement global exception handling in our .NET application e.g. using custom/built in exception filter or creating our custom middleware using IMiddleware
and implementing its methods.
So every time before and after controller request will come in this middleware and we would add try-catch block here and request would be caught here.
Step 1 :
Create Middleware
public class GlobalExceptionHandler : IMiddleware
{
private readonly ILogger<GlobalExceptionHandler> _logger;
public GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger)
{
_logger = logger;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
try
{
await next(context);
}
catch (Exception ex)
{
string message = ex.Message.ToString();
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
// Log the Exception Details
_logger.LogError($"Exception Details: {message}");
var response = new ExceptionDetails()
{
StatusCode = context.Response.StatusCode,
Message = message,
};
await context.Response.WriteAsync(JsonConvert.SerializeObject(response));
}
}
}
If you are worried about what is
JsonConvert.SerializeObject(response)
Then check post on Play with JSON in .NET via System.Text.Json Library
Step 2 :
Register the Middleware as a Service and then use it in Middleware in Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Register Middleware as a Service
builder.Services.AddTransient<GlobalExceptionHandler>();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
// Add GlobalExceptionHandler middleware
app.UseMiddleware<GlobalExceptionHandler>();
app.MapControllers();
app.Run();
That’s all you need to do. Now you can add any exception by throw new Exception("This is a test exception");
and test it if it works or not
Whenever you're ready, there are 3 ways I can help you:
- Subscribe to my youtube channel : For in-depth tutorials, coding tips, and industry insights.
- Promote yourself to 9,000+ subscribers : By sponsoring this newsletter
- Patreon community : Get access to all of my blogs and articles at one place