Lessons in this course (9)

9. Custom error pages, error codes and user-friendly messages

Intermediate★ Must knowLesson 9 of 9

Principles for what users see:

  • Clear, polite message + what to do next ("We couldn't save your order. Please try again in a minute.").
  • A reference/correlation id the user can quote to support — the same id is in the logs.
  • No stack traces, SQL, server names or file paths (information disclosure).
  • Correct HTTP status codes (404 page returns 404, not 200).
  • Stable error codes for APIs ("errorCode": "credit_limit_exceeded") so clients can react without parsing text; localise messages on the client.

ASP.NET Core MVC error pages:

csharp
app.UseExceptionHandler("/Error");                                 // 500s → ErrorController
app.UseStatusCodePagesWithReExecute("/Error/{0}");                 // 404/403 → same controller, original URL kept

public class ErrorController : Controller
{
    [Route("Error/{code:int?}")]
    public IActionResult Index(int? code)
    {
        var feature = HttpContext.Features.Get<IExceptionHandlerPathFeature>();   // original path + exception (log it)
        ViewBag.RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
        return code switch { 404 => View("NotFound"), 403 => View("Forbidden"), _ => View("ServerError") };
    }
}

ProblemDetails (RFC 9457) for APIs:

json
{
  "type": "https://shop.example.com/errors/credit-limit",
  "title": "Business rule violated",
  "status": 422,
  "detail": "Order exceeds the customer's credit limit.",
  "instance": "/api/orders/1001/approve",
  "errorCode": "credit_limit_exceeded",
  "traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}