RequestContext 3.1.0

dotnet add package RequestContext --version 3.1.0
                    
NuGet\Install-Package RequestContext -Version 3.1.0
                    
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="RequestContext" Version="3.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RequestContext" Version="3.1.0" />
                    
Directory.Packages.props
<PackageReference Include="RequestContext" />
                    
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 RequestContext --version 3.1.0
                    
#r "nuget: RequestContext, 3.1.0"
                    
#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 RequestContext@3.1.0
                    
#: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=RequestContext&version=3.1.0
                    
Install as a Cake Addin
#tool nuget:?package=RequestContext&version=3.1.0
                    
Install as a Cake Tool

RequestContext

✨ RequestContext

<p align="center"> <b>Clean request utilities for ASP.NET Core (.NET 8)</b><br/> Correlation Id • Global Exception Handling • Per-Resource Request Locking • Request Metadata Access </p>


🌟 Overview

RequestContext helps you build safer and more observable APIs by providing ready-to-use middleware and extensions.

Core capabilities

  • 🔎 Correlation id propagation (X-Correlation-Id)
  • 🚨 Global exception handling with consistent JSON response
  • 🔐 Per-resource in-memory locking for mutating requests
  • 📦 IRequestContext for user/request metadata in your services

📦 Installation

dotnet add package RequestContext

Package target: .NET 8


🧩 Features in detail

1) Correlation Id Middleware

CorrelationIdMiddleware:

  • Reads X-Correlation-Id from the incoming request
  • Generates a new id if header is missing
  • Sets HttpContext.TraceIdentifier
  • Returns X-Correlation-Id in response headers
  • Adds CorrelationId to logger scope

Use extension:

app.UseCorrelationId();

2) Global Exception Handler Middleware

GlobalExceptionHandlerMiddleware catches unhandled exceptions and writes JSON response payloads.

Default status mapping:

  • ArgumentException400 BadRequest
  • UnauthorizedAccessException401 Unauthorized
  • KeyNotFoundException404 NotFound
  • any other exception → 500 InternalServerError

Use extension:

app.UseGlobalExceptionHandler();

3) Resource Lock Middleware (in-memory)

ResourceLockMiddleware prevents concurrent updates to the same logical resource.

How it works:

  • Applies only to mutating HTTP methods by default: POST, PUT, PATCH, DELETE
  • Skips excluded paths by default: /health, /metrics
  • Resolves lock key from endpoint metadata ([ResourceLockKey(...)])
  • Uses an in-memory SemaphoreSlim lock store per key
  • If lock wait times out, returns 503 JSON response

Default timeout: 30s

Use extensions:

builder.Services.AddResourceLock();
app.UseResourceLock();

4) IRequestContext

Inject IRequestContext in your services to read:

  • CorrelationId
  • UserName
  • ClientIp
  • UserAgent
  • IsAuthenticated

Register with:

builder.Services.AddRequestContext();

🚀 Full Quick Start

Program.cs

using RequestContext.DependancyInjection;
using RequestContext.CorrelationId;
using RequestContext.GlobalExceptionHandler;
using RequestContext.Locking;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddRequestContext();

builder.Services.AddResourceLock(options =>
{
    options.WaitTimeout = TimeSpan.FromSeconds(15);
    // options.ExcludedPaths.Add("/swagger");
});

var app = builder.Build();

app.UseRouting();
app.UseGlobalExceptionHandler();
app.UseCorrelationId();
app.UseResourceLock();

app.MapControllers();
app.Run();

✅ Recommended order:

  1. UseRouting()
  2. UseGlobalExceptionHandler()
  3. UseCorrelationId()
  4. UseResourceLock()
  5. MapControllers()

UseResourceLock() must run after routing and before endpoint execution so endpoint metadata is available.


🔐 Using [ResourceLockKey]

Apply ResourceLockKeyAttribute on controller actions to decide how lock keys are created.

From route parameter

[HttpPut("orders/{id:long}")]
[ResourceLockKey(ResourceLockKeySource.RouteParam, "id")]
public async Task<IActionResult> UpdateOrder(long id, UpdateOrderRequest request)
{
    // Only one update for this order id at a time
    return Ok();
}

From request header

[HttpPost("payments")]
[ResourceLockKey(ResourceLockKeySource.Header, "X-Client-Request-Id")]
public IActionResult CreatePayment(CreatePaymentRequest request)
{
    return Ok();
}

From selected body fields

[HttpPost("inventory/reserve")]
[ResourceLockKey(ResourceLockKeySource.BodyFields, "sku", "warehouse.id")]
public IActionResult Reserve(ReserveInventoryRequest request)
{
    return Ok();
}

From entire body hash

[HttpPost("checkout")]
[ResourceLockKey(ResourceLockKeySource.BodyHash)]
public IActionResult Checkout(CheckoutRequest request)
{
    return Ok();
}

⚙️ Resource lock options

ResourceLockOptions supports:

  • WaitTimeout (TimeSpan) — default 30s
  • LockMethods (HashSet<string>) — default POST, PUT, PATCH, DELETE
  • ExcludedPaths (List<string>) — default /health, /metrics

Example:

builder.Services.AddResourceLock(options =>
{
    options.WaitTimeout = TimeSpan.FromSeconds(10);
    options.LockMethods = new(StringComparer.OrdinalIgnoreCase) { "POST", "PUT" };
    options.ExcludedPaths.Add("/internal/status");
});

📝 Using IRequestContext in application services

public class AuditService
{
    private readonly IRequestContext _requestContext;

    public AuditService(IRequestContext requestContext)
    {
        _requestContext = requestContext;
    }

    public void WriteAudit()
    {
        var correlationId = _requestContext.CorrelationId;
        var userName = _requestContext.UserName;
        var clientIp = _requestContext.ClientIp;
        var userAgent = _requestContext.UserAgent;
        var isAuthenticated = _requestContext.IsAuthenticated;
    }
}

📌 Notes

  • Locking implementation is in-memory and intended for single-instance scenarios.
  • IdempotencyAttribute exists in the package, but idempotency middleware is not part of the current pipeline implementation.

📚 Dependencies

Current package references include:

  • Microsoft.AspNetCore.App (framework reference)
  • Microsoft.EntityFrameworkCore
  • Microsoft.Extensions.Logging.Abstractions
  • StackExchange.Redis

📄 License

Use according to the repository/package license.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  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.

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
3.1.0 102 6/19/2026 3.1.0 is deprecated because it is no longer maintained.
3.0.0 77 6/19/2026
2.1.1 88 6/18/2026
2.1.0 69 6/18/2026
2.0.1 63 6/18/2026
2.0.0 80 6/18/2026
1.2.0 85 6/18/2026
1.0.0 92 6/10/2026 1.0.0 is deprecated because it has critical bugs.