< Summary

Information
Class: Intentum.AspNetCore.BehaviorObservationOptions
Assembly: Intentum.AspNetCore
File(s): /home/runner/work/Intentum/Intentum/src/Intentum.AspNetCore/BehaviorObservationMiddleware.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 5
Coverable lines: 5
Total lines: 73
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 4
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor()0%440%

File(s)

/home/runner/work/Intentum/Intentum/src/Intentum.AspNetCore/BehaviorObservationMiddleware.cs

#LineLine coverage
 1using Intentum.Core.Behavior;
 2using Microsoft.AspNetCore.Http;
 3
 4namespace Intentum.AspNetCore;
 5
 6/// <summary>
 7/// Middleware that automatically observes HTTP request behaviors into a BehaviorSpace.
 8/// </summary>
 9public sealed class BehaviorObservationMiddleware
 10{
 11    private readonly RequestDelegate _next;
 12    private readonly BehaviorSpace _behaviorSpace;
 13    private readonly BehaviorObservationOptions _options;
 14
 15    public BehaviorObservationMiddleware(
 16        RequestDelegate next,
 17        BehaviorSpace behaviorSpace,
 18        BehaviorObservationOptions? options = null)
 19    {
 20        _next = next ?? throw new ArgumentNullException(nameof(next));
 21        _behaviorSpace = behaviorSpace ?? throw new ArgumentNullException(nameof(behaviorSpace));
 22        _options = options ?? new BehaviorObservationOptions();
 23    }
 24
 25    public async Task InvokeAsync(HttpContext context)
 26    {
 27        if (_options.Enabled)
 28        {
 29            var actor = _options.GetActor(context);
 30            var action = _options.GetAction(context);
 31
 32            var metadata = new Dictionary<string, object>
 33            {
 34                { "path", context.Request.Path.Value ?? "" },
 35                { "method", context.Request.Method },
 36                { "statusCode", context.Response.StatusCode }
 37            };
 38
 39            if (_options.IncludeHeaders && context.Request.Headers.Any())
 40            {
 41                metadata["headers"] = context.Request.Headers
 42                    .ToDictionary(h => h.Key, h => (object)h.Value.ToString());
 43            }
 44
 45            _behaviorSpace.Observe(new BehaviorEvent(
 46                actor,
 47                action,
 48                DateTimeOffset.UtcNow,
 49                metadata));
 50        }
 51
 52        await _next(context);
 53    }
 54}
 55
 56/// <summary>
 57/// Options for behavior observation middleware.
 58/// </summary>
 59public sealed class BehaviorObservationOptions
 60{
 61    /// <summary>Whether observation is enabled. Defaults to true.</summary>
 062    public bool Enabled { get; set; } = true;
 63
 64    /// <summary>Whether to include request headers in metadata. Defaults to false.</summary>
 065    public bool IncludeHeaders { get; set; } = false;
 66
 67    /// <summary>Function to extract actor from HTTP context. Defaults to "http".</summary>
 068    public Func<HttpContext, string> GetActor { get; set; } = _ => "http";
 69
 70    /// <summary>Function to extract action from HTTP context. Defaults to method + path.</summary>
 071    public Func<HttpContext, string> GetAction { get; set; } = ctx =>
 072        $"{ctx.Request.Method.ToLowerInvariant()}_{ctx.Request.Path.Value?.Replace("/", "_").TrimStart('_') ?? "root"}";
 73}