In this new post, I like to show how handling exceptions globally with NET6 adding a single class.
Generally, we handled all expected exceptions with try-catch wherever necessary in the code. When our code throws an exception, we need to map that exception. An exception is thrown in the lower layer like data access. You need to map that for all the layers until the presentation layer.
Or you have a bigger problem, losing the exception. Usually, you return a HTTP 500 status code, an internal error. But no one knows the error until checking the logging/tracing. Assuming you have logging/tracing.
So, having a global handling exception allows you to not be concerned about mapping every exception or mapping between layers.
public static class ExceptionMiddleware
{
public static void ConfigureExceptionHandler(this IApplicationBuilder app, bool isDev)
{
app.UseExceptionHandler(appError =>
{
appError.Run(async context =>
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.ContentType = "application/json";
var contextFeature = context.Features.Get<IExceptionHandlerPathFeature>();
if (contextFeature != null)
{
var ex = contextFeature?.Error;
await context.Response.WriteAsync(JsonConvert.SerializeObject(
new ProblemDetails
{
Type = ex.GetType().Name,
Status = (int)HttpStatusCode.InternalServerError,
Instance = contextFeature?.Path,
Title = isDev ? $"{ex.Message}" : "An error occurred.",
Detail = isDev ? ex.StackTrace : null
}));
}
});
});
}
}
The function ConfigureExceptionHandler
receives the IApplicationBuilder
and a variable isDev
from the caller. In line 9, we return the HTTP status code 500, so the front end can be aware of the error.
If the environment is Development, the error message will have the StackTrace (line 24) and the exception message (line 23). But here, you can customize your error message. You also can use another object. You are not stuck with ProblemDetails if you want a different object with different fields and logic, you can do it. ProblemDetails is defined in Microsoft.AspNetCore.Http.Extensions
Register the ConfigureExceptionHandler
Now, we need to register the middleware goes to the Program.cs
or Startup.cs
and type this.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env,
IApiVersionDescriptionProvider provider)
{
// ...
Middlewares(app, env);
}
void Middlewares(IApplicationBuilder app, IWebHostEnvironment env)
{
app.ConfigureExceptionHandler(env.IsDevelopment());
}
After that, if you run your API in development, in case of an internal server error, you get a Json
like the following image.
So, the same code in production returns the following Json
.
Wrap up
In conclusion this is how handling exceptions globally with NET6. Please leave your comment below.
Happy new year!