Handling Exceptions in .NET Core API with Middleware
By FoxLearn 1/14/2025 8:32:42 AM 55
In .NET Core, we’re becoming accustomed to the idea that nothing is provided out of the box. With the flexibility of complete choice, every feature must be implemented by the developer.
It's important to note that you can still catch exceptions in your endpoint using a try...catch block.
namespace MyApp.Controllers { [ApiController] [Route("/api")] [Produces("application/json")] public class ProductController : ControllerBase { [HttpPost()] public IActionResult AddProduct([FromBody] ProductModel product) { try { // Your logic to add the product } catch (Exception ex) { return base.BadRequest(new ProblemDetails() { Title = ex.Message, Detail = ex.ToString() }); } } } }
But what if the exception occurs outside of this part of the controller? For example, what if it happens in a System.Text.Json.Serialization.JsonConverter
before your endpoint is called? The exception will still be thrown, but there’s no default handler, so it won’t be logged or sent to your Application Insights instance.
To handle such scenarios, you should implement middleware. Middleware processes requests and responses, and is commonly used for handling exceptions.
Creating a Custom Middleware to Handle Exceptions
This middleware will catch errors and return the exception as a JSON response. You'll need to add your own logging or Application Insights integration to record the details in your log.
For example, how to implement a middleware that will catch exceptions and return a JSON response with the error details:
using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.Net; using System.Security.Authentication; using System.Threading.Tasks; using Newtonsoft.Json; namespace AppCode { public class JsonExceptionMiddleware { private static readonly Dictionary<Type, HttpStatusCode> _exceptionStatusCodes = new Dictionary<Type, HttpStatusCode> { { typeof(ValidationException), HttpStatusCode.BadRequest }, { typeof(FormatException), HttpStatusCode.BadRequest }, { typeof(AuthenticationException), HttpStatusCode.Forbidden }, { typeof(NotImplementedException), HttpStatusCode.NotImplemented } }; public async Task Invoke(HttpContext context) { var contextFeature = context.Features.Get<IExceptionHandlerFeature>(); if (contextFeature?.Error != null) { // Log the error (you can integrate with your logging or Application Insights here) var exception = contextFeature.Error; var statusCode = GetErrorCode(exception); context.Response.StatusCode = (int)statusCode; context.Response.ContentType = "application/json"; var problemDetails = new ProblemDetails { Status = context.Response.StatusCode, Title = exception.Message, Detail = exception.ToString() }; await context.Response.WriteAsync(JsonConvert.SerializeObject(problemDetails)); } } private static HttpStatusCode GetErrorCode(Exception e) { return _exceptionStatusCodes.TryGetValue(e.GetType(), out var statusCode) ? statusCode : HttpStatusCode.InternalServerError; } } }
Adding the Middleware to the Request Pipeline
To make use of this custom middleware, you need to add it to your application's request pipeline. You can do this in the Configure
method of your Startup.cs
file. The UseExceptionHandler
method allows you to specify the middleware that will handle exceptions.
public void Configure(IApplicationBuilder app) { // Other middleware configurations // Add the custom exception handling middleware app.UseExceptionHandler(new ExceptionHandlerOptions { ExceptionHandler = new JsonExceptionMiddleware().Invoke }); }
With this middleware in place, any unhandled exceptions occurring in your application will be caught, and a JSON response will be returned to the client with the error details. The status code of the response will vary depending on the type of exception that occurred.
Implementing exception handling with middleware in .NET Core allows you to centralize and standardize error responses for your API. By creating a custom JsonExceptionMiddleware
, you ensure that any exceptions occurring during the request processing are caught, logged, and returned in a consistent format.
- Add Thread ID to the Log File using Serilog
- InProcess Hosting in ASP.NET Core
- Limits on ThreadPool.SetMinThreads and SetMaxThreads
- Controlling DateTime Format in JSON Output with JsonSerializerOptions
- ‘s’ is an invalid start of a value. Path: $ in ASP.NET Core
- How to create a Toast Notifications in ASP.NET Core
- How to fix InvalidOperationException: No service for type 'Microsoft.AspNetCore.Identity.UserManager'
- How to fix 'IMvcBuilder' does not contain a definition for 'AddNewtonsoftJson'