RequestContext 3.1.0
dotnet add package RequestContext --version 3.1.0
NuGet\Install-Package RequestContext -Version 3.1.0
<PackageReference Include="RequestContext" Version="3.1.0" />
<PackageVersion Include="RequestContext" Version="3.1.0" />
<PackageReference Include="RequestContext" />
paket add RequestContext --version 3.1.0
#r "nuget: RequestContext, 3.1.0"
#:package RequestContext@3.1.0
#addin nuget:?package=RequestContext&version=3.1.0
#tool nuget:?package=RequestContext&version=3.1.0
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
- 📦
IRequestContextfor 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-Idfrom the incoming request - Generates a new id if header is missing
- Sets
HttpContext.TraceIdentifier - Returns
X-Correlation-Idin response headers - Adds
CorrelationIdto logger scope
Use extension:
app.UseCorrelationId();
2) Global Exception Handler Middleware
GlobalExceptionHandlerMiddleware catches unhandled exceptions and writes JSON response payloads.
Default status mapping:
ArgumentException→400 BadRequestUnauthorizedAccessException→401 UnauthorizedKeyNotFoundException→404 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
SemaphoreSlimlock store per key - If lock wait times out, returns
503JSON response
Default timeout: 30s
Use extensions:
builder.Services.AddResourceLock();
app.UseResourceLock();
4) IRequestContext
Inject IRequestContext in your services to read:
CorrelationIdUserNameClientIpUserAgentIsAuthenticated
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:
UseRouting()UseGlobalExceptionHandler()UseCorrelationId()UseResourceLock()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) — default30sLockMethods(HashSet<string>) — defaultPOST,PUT,PATCH,DELETEExcludedPaths(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.
IdempotencyAttributeexists 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.EntityFrameworkCoreMicrosoft.Extensions.Logging.AbstractionsStackExchange.Redis
📄 License
Use according to the repository/package license.
| Product | Versions 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. |
-
net8.0
- Microsoft.EntityFrameworkCore (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.