Opx.Web.Framework
1.0.4
dotnet add package Opx.Web.Framework --version 1.0.4
NuGet\Install-Package Opx.Web.Framework -Version 1.0.4
<PackageReference Include="Opx.Web.Framework" Version="1.0.4" />
<PackageVersion Include="Opx.Web.Framework" Version="1.0.4" />
<PackageReference Include="Opx.Web.Framework" />
paket add Opx.Web.Framework --version 1.0.4
#r "nuget: Opx.Web.Framework, 1.0.4"
#:package Opx.Web.Framework@1.0.4
#addin nuget:?package=Opx.Web.Framework&version=1.0.4
#tool nuget:?package=Opx.Web.Framework&version=1.0.4
Opx.Web.Framework
Reusable ASP.NET Core middleware for Minimal API, controllers, MVC, Razor Pages, and Blazor Server/Web App hosts. A standalone Blazor WebAssembly client has no ASP.NET Core request pipeline, so install this library in its server or gateway instead.
using Opx.Web.Framework;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpxWebFramework(builder.Configuration);
var app = builder.Build();
app.UseOpxWebFramework();
// authentication, authorization, static files, and application endpoints follow as needed
app.MapOpxWebFramework();
app.Run();
Configuration section:
{
"OpxWebFramework": {
"Correlation": {
"Enabled": true,
"HeaderName": "X-Correlation-ID"
},
"RequestLimits": {
"Enabled": true,
"MaximumBodyBytes": 10485760,
"MaximumTargetLength": 8192,
"MaximumHeaderCount": 100
},
"RateLimiting": {
"Enabled": false,
"PermitLimit": 100,
"WindowSeconds": 60,
"QueueLimit": 0
},
"LogRetention": {
"Enabled": true,
"RetentionDays": 30
},
"ForwardedClientIp": {
"Enabled": true,
"HeaderName": "X-Forwarded-For",
"ForwardLimit": 1,
"KnownProxies": [ "10.0.0.10" ],
"KnownNetworks": [ "10.10.0.0/16" ]
},
"ResponseHeaders": {
"Enabled": true,
"RemoveKestrelServerHeader": true,
"Remove": [ "Server", "X-Powered-By", "X-AspNet-Version", "X-AspNetMvc-Version" ]
},
"ContentSecurityPolicy": {
"Enabled": true,
"ReportOnly": true,
"Preset": "Blazor",
"UseNonce": true
},
"AccessLog": {
"Enabled": true,
"Output": "Logger",
"FilePath": "logs/access-{date}.log",
"IncludeSuspiciousRequests": false,
"ExcludedPaths": [ "/health", "/_framework" ]
},
"EndpointLog": {
"Enabled": true,
"Output": "Logger",
"FilePath": "logs/endpoint-{date}.log",
"IncludeQueryString": true,
"IncludeRouteValues": true,
"SensitiveKeys": [ "password", "token", "secret", "authorization", "key" ],
"ExcludedPaths": [ "/health", "/_framework" ]
},
"StatusCodeRouting": {
"Enabled": true,
"Routes": {
"401": "/account/login",
"403": "/errors/forbidden",
"404": "/errors/not-found"
},
"AppendReturnUrl": true,
"RequireHtmlAcceptHeader": true,
"ExcludedPaths": [ "/api" ]
},
"LogAccess": {
"Enabled": false,
"RoutePrefix": "/opx/logs",
"RequireAuthorization": true,
"AuthorizationPolicy": "LogReader",
"MaximumTake": 1000,
"MaximumRangeDays": 31,
"AccessLogId": "accepted-requests",
"SecurityLogId": "security-events"
},
"SuspiciousTraffic": {
"Enabled": true,
"Block": true,
"StatusCode": 400,
"ResponseFormat": "Auto",
"LogOutput": "Both",
"LogFilePath": "logs/security-{date}.log"
}
}
}
Use UseOpxForwardedClientIp(), UseOpxResponseHeaders(), UseOpxAccessLog(), UseOpxStatusCodeRouting(), UseOpxSuspiciousTrafficGuard(), or UseOpxEndpointLog() when installing features separately. Middleware registration is idempotent, including repeated UseOpxWebFramework() calls. Forwarded client IP must run before logging and traffic inspection. Endpoint logging intentionally excludes request and response bodies.
Call app.MapOpxWebFrameworkLogs() to expose logs by configured logical ID, for example GET /opx/logs/accepted-requests and GET /opx/logs/security-events. There is no directory/source listing endpoint, request paths can never select a physical file, and unknown IDs return 404. Log access is disabled by default and should use an authorization policy in production. File or Both output must be selected for logs that need to be read.
Daily logs use /opx/logs/accepted-requests?date=20260713&take=100. Date-range logs use /opx/logs/accepted-requests/range?from=2026-07-01&to=2026-07-13&takePerDay=100, with the configured security ID used for security logs. Both yyyyMMdd and yyyy-MM-dd are accepted. Results are grouped by date, and range length is limited by MaximumRangeDays.
Call app.MapOpxWebFramework() once to map all enabled framework endpoints, including /health/live, /health/ready, and the optional log reader. Metrics are opt-in and emit opx.http.requests and opx.http.duration through System.Diagnostics.Metrics, suitable for an OpenTelemetry meter subscription named Opx.Web.Framework. Unhandled exceptions return a safe traceable JSON response, and X-Correlation-ID is propagated through response headers, logging scopes, logs, and error responses. Features disabled at startup aren't added to the request pipeline, minimizing overhead; restart the application after enabling one.
CSP supports Api, Mvc, Blazor, and Custom presets. Start with ReportOnly: true, inspect browser violations, then switch it to false. With UseNonce, inject IOpxCspNonceAccessor into a Razor view or component and apply nonce="@CspNonce.Nonce" to trusted script elements. A custom policy can contain {nonce}, which is replaced per request.
When hosted in-process on IIS, IIS can append its own Server header after ASP.NET Core middleware completes. Add the following to the deployed application's web.config when IIS server disclosure must also be disabled:
<system.webServer>
<security>
<requestFiltering removeServerHeader="true" />
</security>
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
</customHeaders>
</httpProtocol>
</system.webServer>
KnownProxies must contain the gateway/reverse-proxy IP, not the visitor IP. The gateway must append the original client address to X-Forwarded-For. If multiple trusted proxy hops exist, list every proxy and adjust ForwardLimit. TrustAllProxies is available for tightly controlled networks but is unsafe on a host directly reachable from the internet because clients can spoof forwarding headers.
Release package
Run ./pack-release.ps1. By default it runs NUnit, increments the patch version, builds a Release NuGet package, verifies the artifact, and only then persists the new version to the project. A build lock prevents two builders from assigning the same version.
Use -Increment Minor or -Increment Major for the corresponding automatic increment, -VersionPrefix 2.0.0 for an explicit SemVer, and -DryRun to preview the calculated metadata without changing files. Existing packages aren't overwritten unless -Force is supplied. -SkipTests is available for CI workflows that already completed the test stage.
Samples
Runnable MVC, Blazor Server, and controller API examples with direct project references are available under samples.
Benchmark and stress test
Run the regular benchmark with ./benchmark/run-benchmark.ps1. For staged ramp-up, sustained soak, SignalR load, EventPipe CPU/memory/GC metrics, and log-growth measurement, run ./benchmark/run-stress-test.ps1. Reports are written under benchmark/results; latest.md and latest-stress.md contain the most recent results.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Opx.Web.Framework:
| Package | Downloads |
|---|---|
|
Opx.Api.Web
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.