< Summary

Information
Class: AsiBackbone.AspNetCore.Correlation.HttpContextAsiBackboneRequestCorrelationResolver
Assembly: AsiBackbone.AspNetCore
File(s): /home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.AspNetCore/Correlation/HttpContextAsiBackboneRequestCorrelationResolver.cs
Line coverage
100%
Covered lines: 42
Uncovered lines: 0
Coverable lines: 42
Total lines: 117
Line coverage: 100%
Branch coverage
83%
Covered branches: 47
Total branches: 56
Branch coverage: 83.9%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)50%66100%
ResolveRequestCorrelation()75%44100%
ResolveCorrelationId(...)100%1010100%
ResolveTraceId(...)50%44100%
ResolveMetadata(...)90.62%3232100%

File(s)

/home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.AspNetCore/Correlation/HttpContextAsiBackboneRequestCorrelationResolver.cs

#LineLine coverage
 1using System.Diagnostics;
 2using AsiBackbone.AspNetCore.DependencyInjection;
 3using Microsoft.AspNetCore.Http;
 4using Microsoft.AspNetCore.Routing;
 5using Microsoft.Extensions.Options;
 6using Microsoft.Extensions.Primitives;
 7
 8namespace AsiBackbone.AspNetCore.Correlation;
 9
 10/// <summary>
 11/// Resolves safe request correlation data from the current ASP.NET Core HTTP context.
 12/// </summary>
 13public sealed class HttpContextAsiBackboneRequestCorrelationResolver : IAsiBackboneHttpRequestCorrelationResolver
 14{
 15    private readonly IHttpContextAccessor httpContextAccessor;
 16    private readonly AsiBackboneAspNetCoreOptions options;
 17
 18    /// <summary>
 19    /// Initializes a new instance of the <see cref="HttpContextAsiBackboneRequestCorrelationResolver" /> class.
 20    /// </summary>
 21    /// <param name="httpContextAccessor">The ASP.NET Core HTTP context accessor.</param>
 22    /// <param name="options">The request correlation options.</param>
 3923    public HttpContextAsiBackboneRequestCorrelationResolver(
 3924        IHttpContextAccessor httpContextAccessor,
 3925        IOptions<AsiBackboneAspNetCoreOptions> options)
 26    {
 3927        this.httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
 3928        this.options = options?.Value ?? throw new ArgumentNullException(nameof(options));
 3929        this.options.Validate();
 3930    }
 31
 32    /// <inheritdoc />
 33    public AsiBackboneHttpRequestCorrelation ResolveRequestCorrelation()
 34    {
 3735        HttpContext? httpContext = httpContextAccessor.HttpContext;
 36
 3737        return httpContext is null
 3738            ? new AsiBackboneHttpRequestCorrelation(traceId: Activity.Current?.Id)
 3739            : new AsiBackboneHttpRequestCorrelation(
 3740            ResolveCorrelationId(httpContext),
 3741            ResolveTraceId(httpContext),
 3742            ResolveMetadata(httpContext));
 43    }
 44
 45    private string? ResolveCorrelationId(HttpContext httpContext)
 46    {
 25847        foreach (string headerName in options.CorrelationIdHeaderNames)
 48        {
 9749            if (string.IsNullOrWhiteSpace(headerName))
 50            {
 51                continue;
 52            }
 53
 9554            if (httpContext.Request.Headers.TryGetValue(headerName, out StringValues values))
 55            {
 1656                string? value = values.FirstOrDefault(static candidate => !string.IsNullOrWhiteSpace(candidate));
 857                if (!string.IsNullOrWhiteSpace(value))
 58                {
 659                    return value.Trim();
 60                }
 61            }
 62        }
 63
 2964        return options.UseHttpContextTraceIdentifierAsCorrelationId
 2965            ? httpContext.TraceIdentifier
 2966            : null;
 667    }
 68
 69    private static string? ResolveTraceId(HttpContext httpContext)
 70    {
 3571        return Activity.Current?.Id ?? httpContext.TraceIdentifier;
 72    }
 73
 74    private Dictionary<string, string> ResolveMetadata(HttpContext httpContext)
 75    {
 3576        Dictionary<string, string> metadata = new(StringComparer.Ordinal);
 77
 3578        if (options.IncludeRequestMethod && !string.IsNullOrWhiteSpace(httpContext.Request.Method))
 79        {
 480            metadata[AsiBackboneHttpRequestMetadataKeys.Method] = httpContext.Request.Method.Trim();
 81        }
 82
 3583        if (options.IncludeRequestPath && httpContext.Request.Path.HasValue)
 84        {
 285            metadata[AsiBackboneHttpRequestMetadataKeys.Path] = httpContext.Request.Path.Value;
 86        }
 87
 3588        Endpoint? endpoint = httpContext.GetEndpoint();
 3589        var routeEndpoint = endpoint as RouteEndpoint;
 90
 3591        if (options.IncludeEndpointDisplayName && !string.IsNullOrWhiteSpace(endpoint?.DisplayName))
 92        {
 493            metadata[AsiBackboneHttpRequestMetadataKeys.EndpointDisplayName] = endpoint.DisplayName.Trim();
 94        }
 95
 3596        if (options.IncludeRoutePattern && !string.IsNullOrWhiteSpace(routeEndpoint?.RoutePattern.RawText))
 97        {
 498            metadata[AsiBackboneHttpRequestMetadataKeys.RoutePattern] = routeEndpoint.RoutePattern.RawText.Trim();
 99        }
 100
 35101        if (options.IncludeRouteValues)
 102        {
 82103            foreach (KeyValuePair<string, object?> routeValue in httpContext.Request.RouteValues)
 104            {
 8105                if (routeValue.Value is null || string.IsNullOrWhiteSpace(routeValue.Key))
 106                {
 107                    continue;
 108                }
 109
 4110                metadata[$"{AsiBackboneHttpRequestMetadataKeys.RouteValuePrefix}{routeValue.Key.Trim()}"] =
 4111                    routeValue.Value.ToString()?.Trim() ?? string.Empty;
 112            }
 113        }
 114
 35115        return metadata;
 116    }
 117}