• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

AndreuCodina / CrossValidation / 5624191041

21 Jul 2023 03:52PM UTC coverage: 95.754% (+0.3%) from 95.463%
5624191041

push

github

AndreuCodina
Publish main branch coverage

405 of 446 branches covered (90.81%)

Branch coverage included in aggregate %.

1354 of 1391 relevant lines covered (97.34%)

180.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.36
/src/CrossValidation/DependencyInjection/CrossValidationMiddleware.cs
1
using System.Net;
2
using System.Text.Json;
3
using CrossValidation.Exceptions;
4
using CrossValidation.Utils;
5
using Microsoft.AspNetCore.Hosting;
6
using Microsoft.AspNetCore.Http;
7
using Microsoft.Extensions.Logging;
8

9
namespace CrossValidation.DependencyInjection;
10

11
public class CrossValidationMiddleware : IMiddleware
12
{
13
    private readonly ILogger<CrossValidationMiddleware> _logger;
14
    private readonly IHostingEnvironment _environment;
15

16
    public CrossValidationMiddleware(ILoggerFactory loggerFactory, IHostingEnvironment environment)
24✔
17
    {
18
        _logger = loggerFactory.CreateLogger<CrossValidationMiddleware>();
24✔
19
        _environment = environment;
24✔
20
    }
24✔
21
    
22
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
23
    {
24
        try
25
        {
26
            await next(context);
24✔
27
        }
×
28
        catch (Exception e)
24✔
29
        {
30
            await HandleException(e, context);
24✔
31
        }
32
    }
24✔
33

34
    private async Task HandleException(Exception exception, HttpContext context)
35
    {
36
        var problemDetails = new CrossProblemDetails();
24✔
37
        var statusCode = HttpStatusCode.InternalServerError;
24✔
38
        string? type = null;
24✔
39
        string? title = null;
24✔
40
        string? details = null;
24✔
41
        List<CrossProblemDetailsError> errors = new();
24✔
42
        
43
        if (exception is BusinessException businessException)
24✔
44
        {
45
            statusCode = businessException.StatusCode;
22✔
46
            title = "A validation error occurred";
22✔
47
            var error = CreateCrossProblemDetailsError(businessException);
22✔
48
            
49
            var allErrorCustomizationsAreNotSet =
22✔
50
                error is
22✔
51
                {
22✔
52
                    Code: null,
22✔
53
                    Message: null,
22✔
54
                    Details: null,
22✔
55
                    Placeholders: null
22✔
56
                };
22✔
57

58
            if (!allErrorCustomizationsAreNotSet)
22✔
59
            {
60
                errors.Add(error);
19✔
61
            }
62
        }
63
        else if (exception is BusinessListException validationListException)
2✔
64
        {
65
            statusCode = HttpStatusCode.UnprocessableEntity;
1✔
66
            title = "Several validation errors occurred";
1✔
67

68
            foreach (var error in validationListException.Exceptions)
2!
69
            {
70
                errors.Add(CreateCrossProblemDetailsError(error));
×
71
            }
72
        }
73
        else if (exception is NonNullablePropertyIsNullException nonNullablePropertyIsNullException)
1!
74
        {
75
            statusCode = HttpStatusCode.BadRequest;
×
76
            title = "Nullability error";
×
77
            details = $"Non nullable property is null: {nonNullablePropertyIsNullException.PropertyName}";
×
78
        }
79
        else if (exception is NonNullableItemCollectionWithNullItemException
1!
80
                 nonNullableItemCollectionWithNullItemException)
1✔
81
        {
82
            statusCode = HttpStatusCode.BadRequest;
×
83
            title = "Nullability error";
×
84
            details = $"Non nullable item collection with null item: {nonNullableItemCollectionWithNullItemException.CollectionName}";
×
85
        }
86
        else
87
        {
88
            if (!CrossValidationOptions.HandleUnknownException)
1!
89
            {
90
                return;
×
91
            }
92
            
93
            _logger.LogError(exception, exception.Message);
1✔
94
            type = "https://datatracker.ietf.org/doc/html/rfc9110#section-15.6.1";
1✔
95
            title = "An error occurred";
1✔
96
            problemDetails.Detail = _environment.IsDevelopment() ? exception.Message : null;
1!
97
        }
98

99
        problemDetails.Status = (int)statusCode;
24✔
100
        problemDetails.Type = type;
24✔
101
        problemDetails.Title = title;
24✔
102
        problemDetails.Detail = details;
24✔
103
        problemDetails.Errors = errors.Any() ? errors : null;
24✔
104
        var response = JsonSerializer.Serialize(problemDetails);
24✔
105
        context.Response.StatusCode = problemDetails.Status.Value;
24✔
106
        context.Response.ContentType = "application/problem+json";
24✔
107
        context.Response.Headers.Add("X-Trace-Id", context.Request.Headers["X-Trace-Id"]);
24✔
108
        await context.Response.WriteAsync(response);
24✔
109
    }
24✔
110

111
    private CrossProblemDetailsError CreateCrossProblemDetailsError(BusinessException exception)
112
    {
113
        var error = new CrossProblemDetailsError
22✔
114
        {
22✔
115
            Code = exception.Code,
22✔
116
            Message = exception.Message == "" ? null : exception.Message,
22✔
117
            Details = exception.Details
22✔
118
        };
22✔
119

120
        if (exception is FrontBusinessException
22!
121
            || (CrossValidationOptions.LocalizeCommonErrorsInFront
22✔
122
                && exception.PlaceholderValues.Count > 0))
22✔
123
        {
124
            var placeholders = new Dictionary<string, object?>();
1✔
125
            
126
            foreach (var placeholder in exception.PlaceholderValues)
6✔
127
            {
128
                placeholders.Add(placeholder.Key, placeholder.Value);
2✔
129
            }
130

131
            error.Placeholders = placeholders;
1✔
132
        }
133

134
        return error;
22✔
135
    }
136
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc