1. Exception Handler

Exception Handler

Unhandled Exception Handler

The library ships with a default exception handler middleware you can use to log the exception details on the server and return a user-friendly HTTP 500 response to the requesting client.

Example JSON Response:

json
{
	"Status": "Internal Server Error!",
	"Code": 500,
	"Reason": "'x' is an invalid start of a value. Path: $.ValMin | LineNumber: 4...",
	"Note": "See application log for stack trace."
}

Example Server Log Entry:

fail: FastEndpoints.ExceptionHandler[0]
      =================================
      HTTP: POST /inventory/adjust-stock
      TYPE: JsonException
      REASON: 'x' is an invalid start of a value. Path: $.ValMin | LineNumber: 4...
      ---------------------------------
         at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state,...
         at System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader,...
         at System.Text.Json.JsonSerializer.ReadCore[TValue](JsonConverter jsonConverter,...
         ...

Enabling The Exception Handler

Enable the middleware as shown below during app startup.

Program.cs
var builder = WebApplication.CreateBuilder();
builder.Services.AddFastEndpoints();

var app = builder.Build();
app.UseDefaultExceptionHandler(); //add this
app.UseAuthorization();
app.UseFastEndpoints();
app.Run();

Disable the ASP.NET Core Diagnostic logging for unhandled exceptions in order to avoid duplicate log entries.

appsettings.json
{
  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware": "None" //add this
    }
}

Customizing The Exception Handler

If you'd like to modify the behavior of the above middleware, you can simply copy the source code and register your version instead.

Disable Validation Error Catching

By default, all validation errors thrown by the endpoints are caught internally and not thrown out to the middleware pipeline. If you need those thrown, you can instruct the endpoint to do so by doing the following:

MyEndpoint.cs
public override void Configure()
{
    Get("throw-error");
    DontCatchExceptions();
}

Do note however that by doing so, you are effectively disabling the automatic error responses sent by the library. It would then be the responsibility of your custom exception handling middleware to handle the exceptions and send appropriate responses to the requesting client.

The thrown exception type is ValidationFailureException, which has a property called Failures where you can get access to a collection of ValidationFailure objects to check what sort of validation failures occurred.

The Better Approach

Instead of using a custom exception handling middleware, you could register a global post-processor like the following:

ErrorLoggerPostProcessor.cs
public class ErrorLogger : IGlobalPostProcessor
{
    public Task PostProcessAsync(object req, object res, HttpContext ctx, IReadOnlyCollection<ValidationFailure> failures, CancellationToken ct)
    {
        if (failures.Count > 0)
        {
            var logger = ctx.Resolve<ILogger<ErrorLogger>>();
            logger.LogWarning("Validation error count: {@count}", failures.Count);
        }
        return Task.CompletedTask;
    }
}

Wire it up in app startup like so:

Program.cs
app.UseFastEndpoints(c =>
{
    c.Endpoints.Configurator = ep =>
    {
        ep.PostProcessors(new ErrorLogger());
    };
});

© FastEndpoints 2022