Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hellang.Middleware.ProblemDetails does not display detail element after the project is published

In development environment it is displaying the error as

{
    "type": "https://httpstatuses.com/401",
    "title": "Unauthorized",
    "status": 401,
    "detail": "LOGIN",  -- this is where I send detail of the error
    "errors": [
        {
            error-stack
        } ...

Once published, not only is the errors element missing, even the detail is also missing.

{
    "type": "https://httpstatuses.com/401",
    "title": "Unauthorized",
    "status": 401,
    "traceId": "|b1bda8d6-44744a1efb1ef714."
}

How can I always have the detail element enabled?

like image 271
dhiman Avatar asked Oct 27 '25 07:10

dhiman


1 Answers

Appreciate that you have probably found a solution by now, but I came across the same issue yesterday and needed a solution!

After looking at the code on GitHub have come up with the following.

In your Startup.cs I assume you'll have something along the lines of:

private void ConfigureProblemDetails(ProblemDetailsOptions options)
{
    // Custom exception to status code mappings
    options.MapToStatusCode<ArgumentException>(StatusCodes.Status400BadRequest);
    options.MapToStatusCode<InvalidOperationException>(StatusCodes.Status400BadRequest);
    options.MapToStatusCode<BadPasswordException>(StatusCodes.Status401Unauthorized);
    options.MapToStatusCode<NotImplementedException>(StatusCodes.Status501NotImplemented);

    // Because exceptions are handled polymorphically, this will act as a "catch all" mapping, which is why it's added last.
    options.MapToStatusCode<Exception>(StatusCodes.Status500InternalServerError);
}

Where MapToStatusCode is an extension method that is built into the Hellang Middleware library.

In the library extension method, the 'detail' property is not set in the MapToStatusCode extension, and is only added if we are in the development environment where options.IncludeExceptionDetails = true, problem is this also exposes the stack trace which we don't want.

The solution then is to create our own extension method. The samples on GitHub give us the general idea.

public static void MapToStatusCodeWithDetail<TException>(this ProblemDetailsOptions options, int statusCode) where TException : Exception
{
    options.Map<TException>((ctx, ex) =>
    {
        var factory = ctx.RequestServices.GetRequiredService<ProblemDetailsFactory>();

        return factory.CreateProblemDetails(ctx, statusCode, detail: ex.Message);
    });
}

Notice above that we explicitly set the detail property to ex.Message.

We can then plumb this in as follows:

private void ConfigureProblemDetails(ProblemDetailsOptions options)
{
    // Custom exception to status code mappings
    options.MapToStatusCodeWithDetail<ArgumentException>(StatusCodes.Status400BadRequest);
    options.MapToStatusCodeWithDetail<InvalidOperationException>(StatusCodes.Status400BadRequest);
    options.MapToStatusCodeWithDetail<BadPasswordException>(StatusCodes.Status401Unauthorized);
    options.MapToStatusCodeWithDetail<NotImplementedException>(StatusCodes.Status501NotImplemented);

    // Because exceptions are handled polymorphically, this will act as a "catch all" mapping, which is why it's added last.
    options.MapToStatusCodeWithDetail<Exception>(StatusCodes.Status500InternalServerError);
}

And we are golden.

As a bonus, to test this in the development environment you can temporarily add the following line when configuring the Hellang Middleware.

options.IncludeExceptionDetails = (ctx, ex) => false;

After which when an exception is thrown in development, you will get the detail property, but not the exception details.

like image 169
mpj Avatar answered Oct 28 '25 20:10

mpj



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!