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

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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • 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.

Version Downloads Last Updated
1.0.4 128 7/16/2026
1.0.3 187 7/13/2026