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

AndreuCodina / CrossValidation / 5596591631

19 Jul 2023 08:05AM UTC coverage: 93.794%. First build
5596591631

Pull #49

github

web-flow
Merge 200b46f5c into d3b2ca8c3
Pull Request #49: First version: business exception source generator

395 of 436 branches covered (90.6%)

Branch coverage included in aggregate %.

516 of 516 new or added lines in 35 files covered. (100.0%)

1328 of 1401 relevant lines covered (94.79%)

169.78 hits per line

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

76.99
/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 bool _isExceptionHandled = false;
14
    private readonly ILogger<CrossValidationMiddleware> _logger;
15
    private readonly IHostingEnvironment _environment;
16

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

33
            if (!_isExceptionHandled)
22!
34
            {
35
                throw;
×
36
            }
37
        }
38
    }
22✔
39

40
    private async Task HandleException(Exception exception, HttpContext context)
41
    {
42
        var problemDetails = new CrossProblemDetails();
22✔
43
        var statusCode = HttpStatusCode.InternalServerError;
22✔
44
        string? title = null;
22✔
45
        string? details = null;
22✔
46
        List<CrossProblemDetailsError> errors = new();
22✔
47

48
        if (exception is BusinessException businessException)
22✔
49
        {
50
            _isExceptionHandled = true;
20✔
51
            statusCode = businessException.StatusCode;
20✔
52
            title = "A validation error occurred";
20✔
53
            var error = CreateCrossProblemDetailsError(businessException);
20✔
54
            
55
            var allErrorCustomizationsAreNotSet =
20✔
56
                error is
20✔
57
                {
20✔
58
                    Code: null,
20✔
59
                    Message: null,
20✔
60
                    Details: null,
20✔
61
                    Placeholders: null
20✔
62
                };
20✔
63

64
            if (!allErrorCustomizationsAreNotSet)
20✔
65
            {
66
                errors.Add(error);
17✔
67
            }
68
        }
69
        else if (exception is ValidationListException validationListException)
2✔
70
        {
71
            _isExceptionHandled = true;
1✔
72
            statusCode = HttpStatusCode.UnprocessableEntity;
1✔
73
            title = "Several validation errors occurred";
1✔
74

75
            foreach (var error in validationListException.Exceptions)
2!
76
            {
77
                errors.Add(CreateCrossProblemDetailsError(error));
×
78
            }
79
        }
80
        else if (exception is NonNullablePropertyIsNullException nonNullablePropertyIsNullException)
1!
81
        {
82
            _isExceptionHandled = true;
×
83
            statusCode = HttpStatusCode.BadRequest;
×
84
            title = "Nullability error";
×
85
            details = $"Non nullable property is null: {nonNullablePropertyIsNullException.PropertyName}";
×
86
        }
87
        else if (exception is NonNullableItemCollectionWithNullItemException
1!
88
                 nonNullableItemCollectionWithNullItemException)
1✔
89
        {
90
            _isExceptionHandled = true;
×
91
            statusCode = HttpStatusCode.BadRequest;
×
92
            title = "Nullability error";
×
93
            details = $"Non nullable item collection with null item: {nonNullableItemCollectionWithNullItemException.CollectionName}";
×
94
        }
95
        else
96
        {
97
            if (!CrossValidationOptions.HandleUnknownException)
1!
98
            {
99
                return;
×
100
            }
101
            
102
            _isExceptionHandled = true;
1✔
103
            _logger.LogError(exception, exception.Message);
1✔
104
            title = "An error occurred";;
1✔
105
            problemDetails.Detail = _environment.IsDevelopment() ? exception.Message : null;
1!
106
        }
107

108
        problemDetails.Status = (int)statusCode;
22✔
109
        problemDetails.Title = title;
22✔
110
        problemDetails.Detail = details;
22✔
111
        problemDetails.Errors = errors.Any() ? errors : null;
22✔
112
        var response = JsonSerializer.Serialize(problemDetails);
22✔
113
        context.Response.StatusCode = problemDetails.Status.Value;
22✔
114
        context.Response.ContentType = "application/problem+json";
22✔
115
        context.Response.Headers.Add("X-Trace-Id", context.Request.Headers["X-Trace-Id"]);
22✔
116
        await context.Response.WriteAsync(response);
22✔
117
    }
22✔
118

119
    private CrossProblemDetailsError CreateCrossProblemDetailsError(BusinessException exception)
120
    {
121
        var error = new CrossProblemDetailsError
20✔
122
        {
20✔
123
            Code = exception.Code,
20✔
124
            Message = exception.Message == "" ? null : exception.Message,
20✔
125
            Details = exception.Details
20✔
126
        };
20✔
127

128
        if (CrossValidationOptions.LocalizeErrorInClient
20!
129
            && exception.PlaceholderValues.Count > 0)
20✔
130
        {
131
            var placeholders = new Dictionary<string, object>();
×
132
            
133
            foreach (var placeholder in exception.PlaceholderValues)
×
134
            {
135
                placeholders.Add(placeholder.Key, placeholder.Value);
×
136
            }
137

138
            error.Placeholders = placeholders;
×
139
        }
140

141
        return error;
20✔
142
    }
143
}
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