Reusable middleware, extensions, and utilities for ASP.NET Core Web APIs. Bundles the boilerplate that every production API needs — logging, CORS, rate limiting, compression, versioning, OpenTelemetry, health checks, exception handling, and a full middleware pipeline — into a single NuGet package.
Targets: net8.0 · net9.0 · net10.0
dotnet add package G3Software.Net.AspNetCore.Core
// Program.csvarbuilder=WebApplication.CreateBuilder(args);builder.AddG3Logging();builder.AddG3Cors();builder.AddG3RateLimiting();builder.AddG3ResponseCompression();builder.AddG3ApiVersioning();builder.AddG3OpenTelemetry("MyApi","1.0.0");builder.Services.AddHealthChecks();builder.Services.AddG3FluentValidation(typeof(Program).Assembly);builder.Services.AddG3CurrentUserModelBinding<AppUser,AppUserResolver>();varapp=builder.Build();app.UseG3CoreMiddleware();app.MapControllers();app.MapG3HealthChecks();app.Run();Applies middleware in the correct order in a single call:
GlobalExceptionHandler → ResponseCompression → OutputCache →
ForwardedHeaders (non-dev) → CORS → SecurityHeaders → RateLimiter →
BotProtection → CorrelationId → Authentication → UserContext → Authorization
- GlobalExceptionHandlerMiddleware — catches all unhandled exceptions, maps them to HTTP status codes, and returns a consistent
ApiErrorJSON response with a uniqueeventIdfor log correlation. - SecurityHeadersMiddleware — injects
X-Content-Type-Options,X-Frame-Options,Referrer-Policy, and a CSP (relaxed in Development, strict in Production). - BotProtectionMiddleware — blocks IPs that generate 10+ 404s within 5 minutes for 15 minutes.
- CorrelationIdMiddleware — propagates or generates
X-Request-IDandX-Session-ID, adds them to the logging scope and response headers. - UserContextMiddleware — extracts the user ID from JWT claims (
sub/NameIdentifier) and stores it inHttpContext.Items.
Extend ApiException to create typed, structured errors:
publicclassRecipeNotFoundException:ApiException{publicRecipeNotFoundException(intid):base("SR_1001",$"Recipe {id} was not found.","Recipe not found."){}}Every ApiException gets a unique 6-character eventId for correlating the response back to a specific log entry.
- Clears default providers and registers a console logger wrapped in a rate limiter (suppresses repeated DB auth errors to 1/minute).
- Sets minimum level to
Warningin Production andInformationin Development. - Filters out high-volume framework categories (
EFCore.Database.Command,AspNetCore.Routing, etc.) to reduce log costs on paid services like CloudWatch.
Registers three named policies bound from the Cors configuration section:
| Policy | Used when | Behavior |
|---|---|---|
Development | IsDevelopment() | Allows localhost origins, any method/header |
Production | default | Strict whitelist from config |
MobileApp | opt-in | Allows custom app schemes + localhost |
UseG3Cors() automatically selects Development or Production based on environment.
// appsettings.json
{
"Cors": {
"AllowedOrigins": ["https://myapp.com"],
"AllowedMethods": ["GET", "POST", "PUT", "DELETE"],
"AllowedHeaders": ["Content-Type", "Authorization"],
"AllowCredentials": true,
"ExposedHeaders": ["X-Request-ID"],
"PreflightMaxAgeHours": 24
}
}- Global policy: 100 requests/minute per IP (queue depth 10).
loginpolicy: 5 requests/15 minutes per IP — apply with[EnableRateLimiting("login")].- Returns
429 Too Many Requestswith aRetry-Afterheader.
- Traces and metrics with ASP.NET Core + HTTP client instrumentation.
- Excludes
/healthendpoints from traces. - Console exporter in Development; OTLP exporter when
OTEL_EXPORTER_OTLP_ENDPOINTis set.
Maps three endpoints with a JSON response writer:
| Endpoint | Tag filter |
|---|---|
/health | all checks |
/health/live | live tag |
/health/ready | ready tag |
Add your own checks with the standard IHealthChecksBuilder API and tag them live or ready as appropriate.
Configures Asp.Versioning.Mvc with URL segment, query string (api-version), and header (x-api-version) readers. Default version is 1.0, format is 'v'VVV.
Registers FluentValidation with auto-validation for all validators found in the given assembly.
builder.Services.AddG3FluentValidation(typeof(Program).Assembly);Resolve the current authenticated user directly into a controller action parameter.
1. Implement ICurrentUserResolver<TUser>:
publicclassAppUserResolver:ICurrentUserResolver<AppUser>{publicasyncTask<AppUser?>ResolveAsync(stringuserId,CancellationTokenct)=>await_db.Users.FindAsync(userId,ct);}2. Register:
builder.Services.AddG3CurrentUserModelBinding<AppUser,AppUserResolver>();3. Use in controllers:
[HttpGet("me")]publicIActionResultGetProfile([FromCurrentUser]AppUseruser)=>Ok(user);Enables Gzip and Brotli compression at Fastest level for application/json and standard web content types.
| Section | Type | Description |
|---|---|---|
Cors | CorsConfiguration | Origins, methods, headers, credentials |
- G3Software.Net.AspNetCore.Aws — AWS Cognito auth, S3/Secrets Manager health checks, Npgsql with RDS secret rotation