< Summary - AsyncResponse (Release / net8.0+net10.0 / unit+integration)

Information
Class: AsyncResponse.Transports.NATS.NatsCorrelationIdExtractor
Assembly: AsyncResponse.Transports.NATS
File(s): /home/runner/work/AsyncResponse/AsyncResponse/src/Transports/AsyncResponse.Transports.NATS/NatsCorrelationIdExtractor.cs
Line coverage
100%
Covered lines: 51
Uncovered lines: 0
Coverable lines: 51
Total lines: 108
Line coverage: 100%
Branch coverage
100%
Covered branches: 46
Total branches: 46
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
Extract(...)100%1818100%
TryReadPath(...)100%1212100%
TryGetProperty(...)100%66100%
UnwrapJsonString(...)100%1010100%

File(s)

/home/runner/work/AsyncResponse/AsyncResponse/src/Transports/AsyncResponse.Transports.NATS/NatsCorrelationIdExtractor.cs

#LineLine coverage
 1using System.Text.Json;
 2using System.Text.Json.Nodes;
 3
 4namespace AsyncResponse.Transports.NATS;
 5
 6/// <summary>
 7/// Extracts the AsyncResponse correlation id from an inbound response message: first from the
 8/// configured NATS header, then from the JSON body via the configured paths.
 9/// </summary>
 10internal static class NatsCorrelationIdExtractor
 11{
 12    /// <summary>Extracts the correlation id from the supplied message.</summary>
 13    public static string? Extract(
 14        IReadOnlyDictionary<string, string>? headers,
 15        string messageJson,
 16        NatsAsyncResponseTransportOptions options)
 17    {
 318        var headerName = NatsTransportOptionsValidator.Required(options.CorrelationIdHeader, nameof(options.CorrelationI
 19
 320        if (headers is not null && headers.TryGetValue(headerName, out var headerValue) && !string.IsNullOrWhiteSpace(he
 321            return headerValue;
 22
 323        var jsonPaths = options.CorrelationIdJsonPaths;
 324        if (jsonPaths is null || jsonPaths.Length == 0 || string.IsNullOrWhiteSpace(messageJson))
 325            return null;
 26
 27        JsonNode? root;
 28        try
 29        {
 330            root = JsonNode.Parse(messageJson);
 331        }
 332        catch (JsonException)
 33        {
 334            return null;
 35        }
 36
 337        if (root is null)
 338            return null;
 39
 340        foreach (var path in jsonPaths)
 41        {
 342            var value = TryReadPath(root, path);
 343            if (!string.IsNullOrWhiteSpace(value))
 344                return value;
 45        }
 46
 247        return null;
 348    }
 49
 50    private static string? TryReadPath(JsonNode root, string path)
 51    {
 352        if (string.IsNullOrWhiteSpace(path))
 353            return null;
 54
 355        var current = root;
 356        foreach (var segment in path.Split('.', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
 57        {
 358            current = UnwrapJsonString(current);
 359            if (current is not JsonObject obj)
 360                return null;
 61
 362            current = TryGetProperty(obj, segment);
 363            if (current is null)
 364                return null;
 65        }
 66
 367        current = UnwrapJsonString(current);
 368        return current switch
 369        {
 370            JsonValue value when value.TryGetValue<string>(out var s) => s,
 271            JsonValue value => value.ToString(),
 372            _ => null
 373        };
 74    }
 75
 76    private static JsonNode? TryGetProperty(JsonObject obj, string name)
 77    {
 378        if (obj.TryGetPropertyValue(name, out var exact))
 379            return exact;
 80
 281        foreach (var property in obj)
 82        {
 283            if (string.Equals(property.Key, name, StringComparison.OrdinalIgnoreCase))
 284                return property.Value;
 85        }
 86
 287        return null;
 388    }
 89
 90    private static JsonNode? UnwrapJsonString(JsonNode? node)
 91    {
 392        if (node is not JsonValue value || !value.TryGetValue<string>(out var text))
 393            return node;
 94
 395        var trimmed = text.AsSpan().TrimStart();
 396        if (trimmed.Length == 0 || (trimmed[0] != '{' && trimmed[0] != '['))
 397            return node;
 98
 99        try
 100        {
 2101            return JsonNode.Parse(text);
 102        }
 2103        catch (JsonException)
 104        {
 2105            return node;
 106        }
 3107    }
 108}