如何通过自定义异常类设置指定HTTP状态码(解决默认返回500状态码问题)
Got it, let's sort this out for you. The problem right now is that even though your custom UCodeException has a StatusCode property, ASP.NET Core doesn’t automatically pick up on it when an exception is thrown. You need to add explicit exception handling to tell the framework to use that status code in the response. Here are two reliable approaches:
1. Global Exception Middleware (Recommended for App-Wide Handling)
Middleware runs on every request, so it’s perfect for catching all your custom exceptions across the entire application.
Step 1: Create the Middleware Class
public class CustomExceptionMiddleware { private readonly RequestDelegate _next; private readonly ILogger<CustomExceptionMiddleware> _logger; public CustomExceptionMiddleware(RequestDelegate next, ILogger<CustomExceptionMiddleware> logger) { _next = next; _logger = logger; } public async Task InvokeAsync(HttpContext httpContext) { try { await _next(httpContext); } catch (UException ex) { _logger.LogError(ex, "Custom application exception occurred"); await HandleCustomExceptionAsync(httpContext, ex); } catch (Exception ex) { // Catch-all for unexpected errors (still returns 500) _logger.LogError(ex, "Unhandled system exception occurred"); await HandleGenericExceptionAsync(httpContext); } } private static Task HandleCustomExceptionAsync(HttpContext context, UException ex) { context.Response.ContentType = "application/json"; context.Response.StatusCode = ex.StatusCode; var errorResponse = new { StatusCode = ex.StatusCode, Errors = ex.Errors }; return context.Response.WriteAsJsonAsync(errorResponse); } private static Task HandleGenericExceptionAsync(HttpContext context) { context.Response.ContentType = "application/json"; context.Response.StatusCode = StatusCodes.Status500InternalServerError; var errorResponse = new { StatusCode = StatusCodes.Status500InternalServerError, Errors = new[] { "An unexpected error occurred." } }; return context.Response.WriteAsJsonAsync(errorResponse); } }
Step 2: Register the Middleware in Program.cs
Make sure to add this middleware before other request-handling middleware like UseAuthorization or UseEndpoints:
var builder = WebApplication.CreateBuilder(args); // Add your services here (controllers, etc.) builder.Services.AddControllers(); var app = builder.Build(); // Register the custom exception middleware first app.UseMiddleware<CustomExceptionMiddleware>(); // Other middleware (e.g., routing, authorization) app.UseRouting(); app.UseAuthorization(); app.MapControllers(); app.Run();
2. Exception Filter (For Controller/Action-Specific Handling)
If you only want to handle exceptions in specific controllers or actions, use an exception filter instead.
Step 1: Create the Filter Class
public class CustomExceptionFilter : IExceptionFilter { private readonly ILogger<CustomExceptionFilter> _logger; public CustomExceptionFilter(ILogger<CustomExceptionFilter> logger) { _logger = logger; } public void OnException(ExceptionContext context) { if (context.Exception is UException ex) { _logger.LogError(ex, "Custom exception caught in filter"); // Set the response status code and error payload context.Result = new ObjectResult(new { StatusCode = ex.StatusCode, Errors = ex.Errors }) { StatusCode = ex.StatusCode }; // Mark the exception as handled so the framework doesn't return 500 context.ExceptionHandled = true; } } }
Step 2: Register the Filter
- Global registration (applies to all controllers):
builder.Services.AddControllers(options => { options.Filters.Add<CustomExceptionFilter>(); }); - Controller-specific registration:
[TypeFilter(typeof(CustomExceptionFilter))] public class MyController : ControllerBase { // Your actions here }
Why Your Current Code Isn’t Working
By default, ASP.NET Core treats any unhandled exception as a 500 Internal Server Error. Your UCodeException has a StatusCode property, but the framework has no way of knowing to use it unless you explicitly catch the exception and set the response status code yourself.
Test It Out
Now when you throw your exception in the service layer:
throw new UCodeException("Already exist", StatusCodes.Status409Conflict);
Your API will return a 409 Conflict status code with your custom error message, instead of the default 500.
内容的提问来源于stack exchange,提问作者Masksway

