Search code examples
c#.netasp.net-corehttpexception

Why is ProblemDetails not being returned in the HTTP response from my 'IExceptionHandler' implementation`?


I'm trying to implement global exception handling in my ASP.NET Core application. My goal is to catch all unhandled exceptions and return a standardized error response using the ProblemDetails object.

public class GlobalExceptionHandler : IExceptionHandler
{
    private readonly ILogger _logger = Log.ForContext(typeof(GlobalExceptionHandler));

    public async ValueTask<bool> TryHandleAsync(
        HttpContext httpContext,
        Exception exception,
        CancellationToken cancellationToken)
    {
        _logger.Error(exception, "Global Exception Handler");

        var problemDetails = new ProblemDetails
        {
            Status = (int)HttpStatusCode.InternalServerError,
            Title = "An exception occurred",
            Detail = exception.Message
        };

        httpContext.Response.StatusCode = problemDetails.Status.Value;
        httpContext.Response.ContentType = "application/problem+json";

        await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken);

        return true;
    }
}

Problem: The HTTP status code is correctly set to 500, but the ProblemDetails object is not being returned in the response body. Instead, the response body is empty, and the client doesn't receive the expected JSON error details.

Why is the ProblemDetails object not being returned in the response body and how can I ensure that the ProblemDetails object is properly serialized and returned?

Thanks in advance!


Solution

  • Thank you everyone for your answers, they helped me eliminate the possible causes and arrive at a solution. The issue was due to a memory stream being closed before the exception handler could write to it. I had to replace the using MemoryStream blocks to work without the using, and it works fine now. Thanks again!

    Previous code:

    using (var ms = new MemoryStream())
    {
        f.CopyTo(ms);
        r = ms.ToArray();
    }
    

    Changed to:

    var ms = new MemoryStream();
    try
    {
        f.CopyTo(ms);
        r = ms.ToArray();
    }
    finally
    {
        ms.Dispose();
    }