< Summary

Information
Class: ArturRios.Util.WebApi.Middleware.ExceptionMiddleware
Assembly: ArturRios.Util.WebApi
File(s): D:\Repositories\dotnet-webapi-util\src\Middleware\ExceptionMiddleware.cs
Line coverage
56%
Covered lines: 21
Uncovered lines: 16
Coverable lines: 37
Total lines: 67
Line coverage: 56.7%
Branch coverage
50%
Covered branches: 3
Total branches: 6
Branch coverage: 50%
Method coverage
100%
Covered methods: 3
Fully covered methods: 1
Total methods: 3
Method coverage: 100%
Full method coverage: 33.3%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
InvokeAsync()100%1147.05%
HandleException()50%8663.15%

File(s)

D:\Repositories\dotnet-webapi-util\src\Middleware\ExceptionMiddleware.cs

#LineLine coverage
 1using ArturRios.Output;
 2using ArturRios.Util.Http;
 3using Microsoft.AspNetCore.Http;
 4using Microsoft.Extensions.Logging;
 5using Newtonsoft.Json;
 6
 7namespace ArturRios.Util.WebApi.Middleware;
 8
 9/// <summary>
 10/// Catches unhandled exceptions raised further down the pipeline and converts them into a JSON error response,
 11/// logging the exception and quietly ignoring client-initiated request cancellations.
 12/// </summary>
 13/// <param name="next">The next middleware in the pipeline.</param>
 14/// <param name="logger">Used to log unhandled exceptions and cancellations.</param>
 115public class ExceptionMiddleware(RequestDelegate next, ILogger<ExceptionMiddleware> logger) : WebApiMiddleware
 16{
 17    /// <summary>Invokes the next middleware, catching any unhandled exception and writing an error response instead of 
 18    /// <param name="httpContext">The current HTTP context.</param>
 19    public async Task InvokeAsync(HttpContext httpContext)
 120    {
 21        try
 122        {
 123            await next(httpContext);
 024        }
 025        catch (OperationCanceledException oce) when (httpContext.RequestAborted.IsCancellationRequested)
 026        {
 027            logger.LogDebug("Request was canceled by the client: {OceMessage}", oce.Message);
 028        }
 029        catch (TaskCanceledException tce) when (httpContext.RequestAborted.IsCancellationRequested)
 030        {
 031            logger.LogDebug("Request was canceled by the client (TaskCanceled): {TceMessage}", tce.Message);
 032        }
 133        catch (Exception ex)
 134        {
 135            await HandleException(httpContext, ex);
 136        }
 137    }
 38
 39    private async Task HandleException(HttpContext context, Exception exception)
 140    {
 141        if (context.RequestAborted.IsCancellationRequested || context.Response.HasStarted)
 042        {
 043            logger.LogDebug(
 044                "Cannot write error response because the request was aborted or the response has already started.");
 45
 046            return;
 47        }
 48
 149        var messages = new[] { "Internal server error, please try again later" };
 50
 151        if (exception is CustomException customException)
 052        {
 053            messages = customException.Messages;
 054        }
 55
 156        logger.LogError(exception, "Unhandled exception while processing the request.");
 57
 158        context.Response.ContentType = "application/json";
 159        context.Response.StatusCode = HttpStatusCodes.InternalServerError;
 60
 161        var output = DataOutput<string>.New
 162            .WithData(string.Empty)
 163            .WithMessages(messages);
 64
 165        await context.Response.WriteAsync(JsonConvert.SerializeObject(output));
 166    }
 67}