Previous Dry Run in Program JIT vs AOT in .NET Core Next

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 Request with validation details for invalid input.
  • Custom Problem Details: Use ProblemDetails for 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.
Back to Index
Previous Dry Run in Program JIT vs AOT in .NET Core Next
*