| ASP.NET Core request processing :👈 | 👉:All about JWT token |
API Error Handling Best Practices in .NET Core |
Robust Error Handling in APIs
Robust error handling in APIs isn’t just a technical necessity; it’s a contract of clarity between your backend and its consumers. Here’s a distilled guide to best practices, tailored for ASP.NET Core Web APIs and extensible to broader RESTful design:
🛠️ Core Best Practices for API Error Handling
1. Use Standard HTTP Status Codes
Ensure your API communicates intent clearly:
| Status Code | Meaning |
|---|---|
| 200 OK | Success |
| 400 Bad Request | Invalid input from client |
| 401 Unauthorized | Missing/invalid credentials |
| 403 Forbidden | Authenticated but not allowed |
| 404 Not Found | Resource doesn’t exist |
| 500 Internal Server Error | Server-side failure |
Avoid using 200 OK for failed operations—it misleads clients.
2. Consistent Error Response Format
Structure your error payloads predictably:
{
"status": 400,
"error": "BadRequest",
"message": "Product name is required.",
"details": [
{
"field": "Name",
"issue": "Must be between 3 and 50 characters."
}
],
"timestamp": "2025-09-19T12:15:00Z",
"requestId": "abc123"
}
This helps consumers parse and log errors uniformly.
3. Global Exception Handling
Use Middleware or ExceptionFilter to catch unhandled exceptions:
public class GlobalExceptionHandlerMiddleware
{
private readonly RequestDelegate _next;
public GlobalExceptionHandlerMiddleware(RequestDelegate next) => _next = next;
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
context.Response.StatusCode = 500;
context.Response.ContentType = "application/json";
var errorResponse = new
{
status = 500,
error = "InternalServerError",
message = ex.Message,
traceId = context.TraceIdentifier
};
await context.Response.WriteAsJsonAsync(errorResponse);
}
}
}
Register it in Startup.cs or Program.cs:
app.UseMiddleware<GlobalExceptionHandlerMiddleware>();
4. Avoid Leaking Sensitive Info
Never expose stack traces, database errors, or internal logic in production. Use generic messages like:
“An unexpected error occurred. Please contact support.”
Log the full details internally, but sanitize the client-facing response.
5. Document Common Errors
Include error codes, formats, and remediation steps in your API docs. Example:
### Error Codes
- ERR001: Invalid input format
- ERR002: Unauthorized access
- ERR003: Resource not found
This empowers consumers to handle errors gracefully.
6. Log Everything (Intelligently)
- Use structured logging (e.g., Serilog, NLog) with correlation IDs
- Include requestId, userId, and timestamp
- Log both handled and unhandled exceptions
- Integrate with monitoring tools (e.g., App Insights, ELK)
7. Fail Fast, Fail Loud
Validate early (e.g., model validation) and return meaningful errors. Don’t let bad data propagate.
🔄 Bonus: Modular Error Handling Strategy
- Create reusable error response builders
- Inject tenant-specific error codes or localization
- Centralize error logging per tenant context
Why Error Handling is Important? in .NET Core
Proper error handling ensures that your API provides clear, consistent, and secure error responses to clients. This improves the developer experience, application reliability, and system security.
Best Practices
- Use Global Exception Handling: Implement a middleware to capture unhandled exceptions.
- Return Standard Error Responses: Follow a consistent error response format using proper HTTP status codes.
- Hide Sensitive Information: Do not expose stack traces or internal server details to clients.
- Use Logging: Log full exception details for troubleshooting.
- Model Validation: Return
400 Bad Requestwith validation details for invalid input. - Custom Problem Details: Use
ProblemDetailsfor a standard error contract.
Best Practices Table
| Error Type | HTTP Status Code | Recommended Response |
|---|---|---|
| Validation Error | 400 Bad Request | {"error":"Invalid input","details":"Name field is required"} |
| Unauthorized | 401 Unauthorized | {"error":"Unauthorized","details":"Valid authentication required"} |
| Forbidden | 403 Forbidden | {"error":"Forbidden","details":"You do not have access to this resource"} |
| Resource Not Found | 404 Not Found | {"error":"Not Found","details":"The requested item was not found"} |
| Conflict | 409 Conflict | {"error":"Conflict","details":"Duplicate entry detected"} |
| Server Error | 500 Internal Server Error | {"error":"Unexpected error","details":"An unexpected error occurred"} |
Example: Global Exception Handling Middleware
using Microsoft.AspNetCore.Http;
using System;
using System.Net;
using System.Text.Json;
using System.Threading.Tasks;
public class ErrorHandlingMiddleware
{
private readonly RequestDelegate _next;
public ErrorHandlingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception ex)
{
var code = HttpStatusCode.InternalServerError; // Default 500
var result = JsonSerializer.Serialize(new
{
error = ex.Message,
details = "An unexpected error occurred. Please try again later."
});
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)code;
return context.Response.WriteAsync(result);
}
}
How to Register Middleware
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseMiddleware<ErrorHandlingMiddleware>();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
Sample Error Response
{
"error": "Object reference not set to an instance of an object.",
"details": "An unexpected error occurred. Please try again later."
}
Summary
- Use middleware for centralized error handling.
- Return standard JSON error responses with HTTP codes.
- Log details internally but return safe messages to clients.
- Validate requests and provide meaningful feedback.
| ASP.NET Core request processing :👈 | 👉:All about JWT token |