< Summary

Information
Class: AsiBackbone.AspNetCore.Correlation.AsiBackboneHttpRequestCorrelation
Assembly: AsiBackbone.AspNetCore
File(s): /home/runner/work/AsiBackbone/AsiBackbone/src/AsiBackbone.AspNetCore/Correlation/AsiBackboneHttpRequestCorrelation.cs
Line coverage
95%
Covered lines: 40
Uncovered lines: 2
Coverable lines: 42
Total lines: 131
Line coverage: 95.2%
Branch coverage
80%
Covered branches: 24
Total branches: 30
Branch coverage: 80%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
.cctor()100%11100%
get_CorrelationId()100%11100%
get_TraceId()100%11100%
get_Metadata()100%11100%
get_HasMetadata()100%210%
ToEvaluationContext(...)100%11100%
MergeMetadata(...)85.71%1414100%
NormalizeOptional(...)100%22100%
NormalizeMetadata(...)87.5%88100%
AddIfValid(...)50%7675%

File(s)

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

#LineLine coverage
 1using System.Collections.ObjectModel;
 2using AsiBackbone.Core.Constraints;
 3
 4namespace AsiBackbone.AspNetCore.Correlation;
 5
 6/// <summary>
 7/// Represents framework-neutral request correlation data resolved from the current ASP.NET Core HTTP request.
 8/// </summary>
 9/// <remarks>
 10/// Initializes a new instance of the <see cref="AsiBackboneHttpRequestCorrelation" /> class.
 11/// </remarks>
 12/// <param name="correlationId">The resolved correlation identifier, when available.</param>
 13/// <param name="traceId">The resolved trace identifier, when available.</param>
 14/// <param name="metadata">Safe request metadata resolved from the host.</param>
 4515public sealed class AsiBackboneHttpRequestCorrelation(
 4516    string? correlationId = null,
 4517    string? traceId = null,
 4518    IReadOnlyDictionary<string, string>? metadata = null)
 19{
 320    private static readonly IReadOnlyDictionary<string, string> EmptyMetadata =
 321        new ReadOnlyDictionary<string, string>(
 322            new Dictionary<string, string>(StringComparer.Ordinal));
 23
 24    /// <summary>
 25    /// Gets the request correlation identifier, when supplied by the host or propagated request headers.
 26    /// </summary>
 7427    public string? CorrelationId { get; } = NormalizeOptional(correlationId);
 28
 29    /// <summary>
 30    /// Gets the request trace identifier, when supplied by the host or current activity.
 31    /// </summary>
 6632    public string? TraceId { get; } = NormalizeOptional(traceId);
 33
 34    /// <summary>
 35    /// Gets safe request metadata supplied by the ASP.NET Core adapter.
 36    /// </summary>
 10237    public IReadOnlyDictionary<string, string> Metadata { get; } = NormalizeMetadata(metadata);
 38
 39    /// <summary>
 40    /// Gets a value indicating whether safe request metadata is available.
 41    /// </summary>
 042    public bool HasMetadata => Metadata.Count > 0;
 43
 44    /// <summary>
 45    /// Creates a framework-neutral constraint evaluation context from the resolved request correlation data.
 46    /// </summary>
 47    /// <param name="policyVersion">Optional policy version.</param>
 48    /// <param name="policyHash">Optional policy hash.</param>
 49    /// <param name="metadata">Optional host-provided metadata to merge with safe request metadata.</param>
 50    /// <returns>A framework-neutral constraint evaluation context.</returns>
 51    public AsiBackboneConstraintEvaluationContext ToEvaluationContext(
 52        string? policyVersion = null,
 53        string? policyHash = null,
 54        IReadOnlyDictionary<string, string>? metadata = null)
 55    {
 1156        return new AsiBackboneConstraintEvaluationContext(
 1157            CorrelationId,
 1158            policyVersion,
 1159            policyHash,
 1160            MergeMetadata(metadata));
 61    }
 62
 63    /// <summary>
 64    /// Merges safe request metadata with host-provided metadata.
 65    /// </summary>
 66    /// <param name="metadata">Optional host-provided metadata.</param>
 67    /// <returns>A normalized metadata dictionary.</returns>
 68    public IReadOnlyDictionary<string, string> MergeMetadata(IReadOnlyDictionary<string, string>? metadata)
 69    {
 1770        if ((metadata is null || metadata.Count == 0) && Metadata.Count == 0)
 71        {
 472            return EmptyMetadata;
 73        }
 74
 1375        Dictionary<string, string> merged = new(StringComparer.Ordinal);
 76
 3877        foreach (KeyValuePair<string, string> item in Metadata)
 78        {
 679            AddIfValid(merged, item.Key, item.Value);
 80        }
 81
 1382        if (metadata is not null)
 83        {
 11084            foreach (KeyValuePair<string, string> item in metadata)
 85            {
 4286                AddIfValid(merged, item.Key, item.Value);
 87            }
 88        }
 89
 1390        return merged.Count == 0
 1391            ? EmptyMetadata
 1392            : new ReadOnlyDictionary<string, string>(merged);
 93    }
 94
 95    private static string? NormalizeOptional(string? value)
 96    {
 9097        return string.IsNullOrWhiteSpace(value)
 9098            ? null
 9099            : value.Trim();
 100    }
 101
 102    private static IReadOnlyDictionary<string, string> NormalizeMetadata(
 103        IReadOnlyDictionary<string, string>? metadata)
 104    {
 45105        if (metadata is null || metadata.Count == 0)
 106        {
 29107            return EmptyMetadata;
 108        }
 109
 16110        Dictionary<string, string> normalizedMetadata = new(StringComparer.Ordinal);
 111
 80112        foreach (KeyValuePair<string, string> item in metadata)
 113        {
 24114            AddIfValid(normalizedMetadata, item.Key, item.Value);
 115        }
 116
 16117        return normalizedMetadata.Count == 0
 16118            ? EmptyMetadata
 16119            : new ReadOnlyDictionary<string, string>(normalizedMetadata);
 120    }
 121
 122    private static void AddIfValid(Dictionary<string, string> metadata, string key, string? value)
 123    {
 72124        if (string.IsNullOrWhiteSpace(key))
 125        {
 0126            return;
 127        }
 128
 72129        metadata[key.Trim()] = value?.Trim() ?? string.Empty;
 72130    }
 131}