Nedo.AspNet.Request.Enrichment 1.0.2

dotnet add package Nedo.AspNet.Request.Enrichment --version 1.0.2
                    
NuGet\Install-Package Nedo.AspNet.Request.Enrichment -Version 1.0.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Nedo.AspNet.Request.Enrichment" Version="1.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Nedo.AspNet.Request.Enrichment" Version="1.0.2" />
                    
Directory.Packages.props
<PackageReference Include="Nedo.AspNet.Request.Enrichment" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Nedo.AspNet.Request.Enrichment --version 1.0.2
                    
#r "nuget: Nedo.AspNet.Request.Enrichment, 1.0.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Nedo.AspNet.Request.Enrichment@1.0.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Nedo.AspNet.Request.Enrichment&version=1.0.2
                    
Install as a Cake Addin
#tool nuget:?package=Nedo.AspNet.Request.Enrichment&version=1.0.2
                    
Install as a Cake Tool

Nedo.AspNet.Request.Enrichment

A middleware-based library for .NET 9 that enriches HTTP requests with contextual metadata — request IDs, correlation IDs, client details, user information, and more — making it available throughout the request lifecycle via dependency injection.

Why Request Enrichment?

In distributed systems, having rich contextual data on every request is critical for:

  • Observability — Correlate logs, traces, and metrics across services.
  • Debugging — Quickly identify the source and context of problematic requests.
  • Security — Track client IPs, user agents, and authentication context.
  • Analytics — Gather structured data about request patterns and usage.

Features

  • 🔌 11 built-in enrichers — Request ID, Correlation ID, Client IP, URL, Timestamp, Client Info, User Info, Machine Info, HTTP Headers, Query Parameters, Request Body
  • 🏗️ Fluent builder API — Type-safe, chainable configuration in Program.cs
  • ⚙️ JSON configuration — Declarative appsettings.json support with validation
  • 🔀 Pipeline strategies — Sequential (default) or Parallel execution
  • 🛡️ Resilience — Configurable retries with exponential backoff, per-enricher timeouts, critical/non-critical failure handling
  • 📤 Response header propagation — Automatically writes X-Request-Id and X-Correlation-Id to response headers
  • 🎯 Conditional enrichmentShouldEnrich(HttpContext) lets enrichers skip requests based on method, path, or conditions
  • 📊 Built-in metricsSystem.Diagnostics.Metrics counters and histograms for observability via OpenTelemetry
  • 🔍 Ambient contextIEnrichmentContextAccessor provides AsyncLocal-based access from background services
  • 🎯 Path filtering — Skip enrichment for health checks, static files, etc.
  • 🧩 Custom enrichers — Implement IRequestEnricher for domain-specific data
  • 💉 DI-first — Strongly-typed EnrichmentContext injectable into controllers, services, and minimal API endpoints
  • Testable — Interface-driven design, easy to mock and unit test

Quick Start

Installation

dotnet add package Nedo.AspNet.Request.Enrichment

Basic Setup

// Program.cs
using Nedo.AspNet.Request.Enrichment.DependencyInjection;
using Nedo.AspNet.Request.Enrichment.Middleware;

builder.Services.AddRequestEnrichment(enrichment =>
{
    enrichment.AddRequestId();
    enrichment.AddCorrelationId();
    enrichment.AddClientIp();
    enrichment.AddRequestTime();
});

app.UseRequestEnrichment();

Access Enriched Data

Minimal API:

app.MapGet("/info", (EnrichmentContext ctx) => new
{
    ctx.RequestId,
    ctx.CorrelationId,
    ctx.ClientIp,
    ctx.RequestTime
});

Controller:

using Nedo.AspNet.Request.Enrichment.Middleware;

[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    private readonly EnrichmentContext _enrichment;
    private readonly ILogger<OrdersController> _logger;

    public OrdersController(
        EnrichmentContext enrichment,
        ILogger<OrdersController> logger)
    {
        _enrichment = enrichment;
        _logger = logger;
    }

    [HttpGet]
    public IActionResult Get()
    {
        _logger.LogInformation(
            "Request {RequestId} from {ClientIp}",
            _enrichment.RequestId,
            _enrichment.ClientIp);

        return Ok(new
        {
            _enrichment.RequestId,
            _enrichment.CorrelationId,
            _enrichment.ClientIp
        });
    }
}

Background Service / Non-DI Access:

using Nedo.AspNet.Request.Enrichment.Abstractions;

public class AuditService
{
    private readonly IEnrichmentContextAccessor _accessor;

    public AuditService(IEnrichmentContextAccessor accessor)
        => _accessor = accessor;

    public void LogAction(string action)
    {
        var ctx = _accessor.EnrichmentContext;
        Console.WriteLine($"[{ctx?.RequestId}] {action} by {ctx?.ClientIp}");
    }
}

Note: The middleware automatically writes X-Request-Id and X-Correlation-Id to every HTTP response header — no extra code needed.

Built-in Enrichers

# Enricher Name Priority Output Type
1 RequestTimeEnricher RequestTime 5 DateTimeOffset
2 RequestIdEnricher RequestId 10 string
3 CorrelationIdEnricher CorrelationId 11 string
4 RequestUrlEnricher RequestUrl 20 string
5 RequestBodyEnricher RequestBody 25 long, string
6 ClientIpEnricher ClientIp 30 string
7 ClientInfoEnricher ClientInfo 40 ClientInfo
8 UserInformationEnricher UserInformation 50 UserInfo
9 MachineInformationEnricher MachineInformation 60 MachineInfo
10 HttpHeaderEnricher HttpHeader 70 IReadOnlyDictionary
11 QueryParameterEnricher QueryParameter 80 IReadOnlyDictionary

Register all at once:

builder.Services.AddRequestEnrichment(enrichment =>
{
    enrichment.AddAllDefaults();
});

Configuration

Fluent API with Per-Enricher Options

builder.Services.AddRequestEnrichment(enrichment =>
{
    enrichment.AddClientIp(options =>
    {
        options.TrustForwardedHeaders = true;
        options.ForwardedHeaderName = "X-Forwarded-For";
    });

    enrichment.AddHttpHeaders(options =>
    {
        options.ExcludeHeaders = ["Authorization", "Cookie", "Set-Cookie"];
    });

    enrichment.AddUserInformation(options =>
    {
        options.IncludeClaims = ["sub", "email", "role"];
    });
});

JSON Configuration

{
  "Enrichment": {
    "EnabledEnrichers": [
      "RequestId", "CorrelationId", "ClientIp",
      "RequestTime", "UserInformation"
    ],
    "EnableDebugLogging": false,
    "Resilience": {
      "MaxRetries": 3,
      "RetryBaseDelayMs": 100,
      "TimeoutMs": 5000
    }
  }
}

Pipeline Strategies

// Sequential (default) — predictable priority ordering
enrichment.UseSequentialPipeline();

// Parallel — concurrent execution for high-throughput
enrichment.UseParallelPipeline(maxConcurrency: 5);

Path Filtering

app.UseRequestEnrichment(options =>
{
    options.ExcludePaths = ["/health", "/ready", "/metrics"];
    options.ExcludeExtensions = [".css", ".js", ".png"];
});

Custom Enrichers

Implement IRequestEnricher for domain-specific data:

public class TenantEnricher : IRequestEnricher
{
    public string Name => "Tenant";
    public int Priority => 15;
    public bool IsCritical => true;

    // Only enrich API routes, skip health checks
    public bool ShouldEnrich(HttpContext context)
        => context.Request.Path.StartsWithSegments("/api");

    public async Task<EnrichmentResult> EnrichAsync(
        HttpContext context,
        CancellationToken cancellationToken = default)
    {
        var tenantId = context.Request.Headers["X-Tenant-Id"].FirstOrDefault();

        if (string.IsNullOrEmpty(tenantId))
            return EnrichmentResult.Failed(Name, "X-Tenant-Id header is required");

        return new EnrichmentResult
        {
            EnricherName = Name,
            Success = true,
            Data = new Dictionary<string, object> { ["TenantId"] = tenantId }
        };
    }
}

Register it:

builder.Services.AddRequestEnrichment(enrichment =>
{
    enrichment.AddAllDefaults();
    enrichment.AddCustom<TenantEnricher>();
});

Project Structure

├── doc/                                       # Documentation (00–08)
├── sample/                                    # Sample projects
│   └── Nedo.AspNet.Request.Enrichment.Sample/
│       └── Controllers/                       # Sample controllers
├── src/                                       # Source code
│   └── Nedo.AspNet.Request.Enrichment/
│       ├── Abstractions/                      # IRequestEnricher, IEnrichmentContextAccessor, Models
│       ├── Enrichers/                         # 11 built-in enrichers
│       ├── Configuration/                     # EnrichmentOptions, EnrichmentBuilder
│       ├── Infrastructure/                    # EnrichmentContextAccessor, EnrichmentMetrics
│       ├── Middleware/                         # EnrichmentMiddleware, EnrichmentContext
│       ├── Pipeline/                          # Sequential + Parallel strategies
│       └── DependencyInjection/               # ServiceCollection + ApplicationBuilder extensions
└── test/                                      # Unit tests (25 tests)

Getting Started

Prerequisites

Build

dotnet build

Run the Sample

dotnet run --project sample/Nedo.AspNet.Request.Enrichment.Sample

Run Tests

dotnet test

Documentation

Doc Title Description
00 Overview Core concepts and quick start
01 Architecture & Design Internal architecture, design patterns, and project structure
02 Enrichers Reference Complete reference for all built-in enrichers
03 Configuration Guide JSON and fluent configuration options
04 Middleware Pipeline How the enrichment pipeline processes requests
05 Custom Enrichers Creating and registering your own enrichers
06 Resilience & Error Handling Retry policies, timeouts, and error strategies
07 Testing Guide Unit and integration testing patterns
08 Migration Guide Migrating from Sindika.AspNet.Enrichment

License

This project is licensed under the MIT License.

Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net9.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.2 83 2/18/2026
1.0.1 86 2/15/2026