Cloudstrap.Mvc
0.2.0-preview.83
Prefix Reserved
dotnet add package Cloudstrap.Mvc --version 0.2.0-preview.83
NuGet\Install-Package Cloudstrap.Mvc -Version 0.2.0-preview.83
<PackageReference Include="Cloudstrap.Mvc" Version="0.2.0-preview.83" />
<PackageVersion Include="Cloudstrap.Mvc" Version="0.2.0-preview.83" />
<PackageReference Include="Cloudstrap.Mvc" />
paket add Cloudstrap.Mvc --version 0.2.0-preview.83
#r "nuget: Cloudstrap.Mvc, 0.2.0-preview.83"
#:package Cloudstrap.Mvc@0.2.0-preview.83
#addin nuget:?package=Cloudstrap.Mvc&version=0.2.0-preview.83&prerelease
#tool nuget:?package=Cloudstrap.Mvc&version=0.2.0-preview.83&prerelease
Cloudstrap.Mvc
Server-rendered MVC bootstrap for ASP.NET Core: controllers + views, hardened session state on stock
Microsoft.AspNetCore.Session, content-negotiated error handling — an error page for browsers,
RFC 9457 problem details for JSON clients — correlation, health probes, security headers, HSTS and
CORS. Two calls and one Cloudstrap:Mvc section.
Zero package dependencies: three Cloudstrap.* project references and the shared
Microsoft.AspNetCore.App framework reference — nothing else.
Quick start
using Cloudstrap.Mvc;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.AddCloudstrapMvc();
WebApplication app = builder.Build();
app.UseCloudstrapMvc();
await app.RunAsync();
Under ten lines: the conventional default route ({controller=Home}/{action=Index}/{id?}) and every
attribute route answer, wwwroot is served, /healthz and /ready probe, every request carries an
ambient correlation id, session state is on and hardened, unhandled exceptions produce the right shape
for every caller, and every response carries the constant security headers.
Supply a minimal error action (no default page ships — see Error handling):
[Route("/error")]
public sealed class ErrorController : Controller
{
[HttpGet]
public IActionResult Get() => View(); // a neutral apology page, no exception content
}
The middleware order
The order is the point of the pipeline call, and it is fixed:
- The error handling head — the developer exception page where selected, otherwise the exception
handler: Cloudstrap's negotiating handler answers JSON-preferring callers terminally, and
HTML-preferring callers get the consumer's page re-executed at
Cloudstrap:Application:ExceptionHandlerPath(default/error). - HSTS — outside
Development, when enabled. - The security-header middleware (
nosniff,no-referrer). - The path base — when
Cloudstrap:Application:PathBaseis set. - Static files — when
UseStaticFilesis on (default). BeforeRoutinghook — the slot for a security-headers bundle, rewrites, or forwarded headers.- Routing.
- CORS — only when origins are configured.
- Correlation (from
Cloudstrap.Observability). - Authentication — only when a scheme is registered.
BeforeAuthorizationhook — the slot for anything that must see the principal first.- Authorization — under the same condition as authentication.
- Session — when
Cloudstrap:Mvc:Session:Enabledis on (default). - Antiforgery.
BeforeEndpointshook.- The conventional default route, attribute routes included — when
MapDefaultControllerRouteis on (default). - Health probes (from
Cloudstrap.Extensions). ConfigureEndpointshook — the slot for minimal APIs, Razor Pages, or asset endpoints.
Every constituent piece stays independently callable (UseStaticFiles, UseSession,
UseCloudstrapCorrelation, MapCloudstrapHealthChecks) — a consumer who needs a different order
simply does not call UseCloudstrapMvc.
Settings
Cloudstrap:Mvc:Session
| Key | Default | Meaning |
|---|---|---|
Enabled |
true |
Session registered and wired at all. false removes it entirely. |
CookieName |
.Cloudstrap.Session |
The session cookie name. |
CookieSecurePolicy |
Always |
Always / SameAsRequest / None. |
IdleTimeoutMinutes |
20 |
Idle minutes before an untouched session is abandoned. Must be > 0. |
IsEssential |
false |
Exempts the cookie from cookie-consent gating. |
Cloudstrap:Mvc:ExceptionHandling
| Key | Default | Meaning |
|---|---|---|
IncludeDetails |
(unset) → Development only |
Exception type/message/stack/inner chain in the JSON payload. Never applies to the HTML page. |
UseDeveloperExceptionPage |
(unset) → Development only |
The framework's developer page instead of the Cloudstrap error contract. |
Cloudstrap:Mvc:Hsts
| Key | Default | Meaning |
|---|---|---|
Enabled |
true |
Emit Strict-Transport-Security outside Development. |
MaxAgeDays |
365 |
The advertised max-age. Must be > 0 while enabled. |
IncludeSubDomains |
true |
Include subdomains in the policy. |
Preload |
false |
The preload token — a domain-owner commitment, never a library default. |
Cloudstrap:Mvc:Cors
| Key | Default | Meaning |
|---|---|---|
AllowedOrigins |
(empty) | Origins allowed cross-origin, credentialed; https://*.contoso.example allows wildcard subdomains. Empty means no CORS is registered at all. |
Owned elsewhere, never redefined here
| Section | Owner | Consumed as |
|---|---|---|
Cloudstrap:Application (PathBase, ExceptionHandlerPath) |
Cloudstrap.Core |
The path base slot; the error re-execution path (default /error). |
Cloudstrap:Correlation |
Cloudstrap.Observability |
The correlation middleware and header. |
Cloudstrap:HealthChecks |
Cloudstrap.Extensions |
/healthz + /ready mapping. |
Configuration ordering: registration-time decisions (session on/off, HSTS/CORS registration) read
builder.Configuration eagerly inside AddCloudstrapMvc. Configuration sources added after the
call — AddCloudstrapKeyVault, for example — do not affect them: call KeyVault first.
Session posture
Session state is on by default and hardened by default, flowing entirely through stock
Microsoft.AspNetCore.Session — this package ships zero session middleware, store or
cookie-protection code, and the cookie stays compatible with the stock one (same DataProtection
purpose). The delta is startup options only:
.Cloudstrap.Session,Securealways,HttpOnly(stock),SameSite=Lax(stock), path-base-scoped path,IsEssential=false, 20-minute idle timeout.- The override ladder: hardened defaults →
Cloudstrap:Mvc:Session→ theCloudstrapMvcConfigurator.Sessionhook (fullSessionOptionsaccess, runs last, final say). - Plain HTTP: with
Securealways on, a browser will not return the cookie over plain HTTP on a non-loopback origin. Develop over HTTPS, or setCookieSecurePolicy: SameAsRequestexplicitly for local HTTP — the default is never silently downgraded. (Loopback —http://127.0.0.1— is a trustworthy origin; browsers accept theSecurecookie there.) IsEssentialand cookie consent: with a consent feature active (Cloudstrap.CookieConsent, deliverable #21), the session cookie is withheld until the visitor consents unless you setIsEssential: true— do that only when session state is genuinely essential.
Multi-instance deployments
The default backing store is the framework's in-memory cache — single-instance only. For more than one instance:
- Register a distributed
IDistributedCache(Redis, SQL Server) beforeAddCloudstrapMvc— the consumer's registration always wins; the in-memory fallback never displaces it. - Call
AddCloudstrapDataProtection(fromCloudstrap.Extensions, deliverable #4) so all instances share the key ring that protects the session cookie.
Single-instance apps need nothing.
Error handling
The contract is content-negotiated. A request is HTML-preferring exactly when its Accept header
contains the text/html or application/xhtml+xml media type — browsers always send text/html on
navigation. Everything else — application/json, */* alone, an absent or unparsable Accept
header — is JSON-preferring.
- HTML-preferring → the consumer's own error page, re-executed at
Cloudstrap:Application:ExceptionHandlerPath(default/error). No default page ships — supply the minimal action from the quick start. The page never carries exception content, whateverIncludeDetailssays. - JSON-preferring →
500 application/problem+jsonwith a generic title and the ambientcorrelationId; withIncludeDetailsresolved true, also the exception type, message, stack trace and a depth-5-bounded inner-exception chain. Never enable details on a public production application. - The failure is logged server-side exactly once on either branch.
- An
IExceptionHandleryou register beforeAddCloudstrapMvcgets the first attempt; Cloudstrap's handler is the terminal fallback.
Security headers
Two constant headers on every response, never overwriting a value the application set:
X-Content-Type-Options: nosniff and Referrer-Policy: no-referrer. There is deliberately no default
CSP or X-Frame-Options — wrong defaults break real applications. For the full HTML bundle, use the
NetEscapades.AspNetCore.SecurityHeaders package through the hook:
app.UseCloudstrapMvc(pipeline => pipeline.BeforeRouting = branch =>
branch.UseSecurityHeaders(policies => policies.AddDefaultSecurityHeaders()));
Recipes
MapStaticAssetsadopters: setUseStaticFiles = falseand map the asset endpoints inConfigureEndpoints.- Forwarded headers (behind a proxy): set the platform's
ASPNETCORE_FORWARDEDHEADERS_ENABLEDenvironment variable, or placeUseForwardedHeadersyourself inBeforeRouting— never a silent library default.
Authentication pairing
AddCloudstrapMvc registers no authentication scheme. Pair it with AddCloudstrapOpenIdConnect
(deliverable #10) or any scheme of your own: whenever a scheme is registered, UseCloudstrapMvc
places the authentication and authorization middleware after routing; with none, every endpoint is
anonymous. There is no forced RequireAuthorization() — endpoint protection belongs to the auth
package's fallback policy or your own [Authorize] attributes.
Not with AddCloudstrapWebApi
UseCloudstrapMvc and UseCloudstrapWebApi are both pipeline owners — a host must not call
both. A host serving MVC pages and a versioned API composes the granular pieces around one owner
instead: pick the composite that matches the host's primary surface and place the other surface's
pieces through the hooks.
Aspire coexistence
Health checks are registered additively on the stock IHealthChecksBuilder, so an Aspire
ServiceDefaults host's checks and Cloudstrap's land in the same set; correlation and probes route
through the already-composable Cloudstrap.Observability/Cloudstrap.Extensions seams. The package
references zero Aspire.* assemblies.
Framework reference
This package carries <FrameworkReference Include="Microsoft.AspNetCore.App" />: it is for server
applications built on the ASP.NET Core shared framework — the runtime image must include ASP.NET Core
(mcr.microsoft.com/dotnet/aspnet), not the bare .NET runtime.
Migrating from the enterprise predecessor
- The session middleware fork is gone. The hardening ships as stock
SessionOptions; the cookie renamesnihdi.session→.Cloudstrap.Session(existing sessions reset once at rollout). - Inbound correlation ids are honored (and generated when absent) via
Cloudstrap.Observability— the source's outbound-onlyCorrelationSourceMiddlewareis not ported. - Browsers get an error page, not raw JSON. The source handler wrote
{StatusCode, Message}JSON to every caller; the contract is now negotiated (see Error handling). - No
AllowAnyOriginfallback. No configured origins now means no CORS at all. - The conventional default route is on by default (the source mapped attribute routes only);
switch it off with
MapDefaultControllerRoute = false. - No forwarded-headers, static-web-assets or path-base magic. Each is explicit configuration or
a hook (see Recipes); the path base comes only from
Cloudstrap:Application:PathBase. - Localization is unbundled — deliverable #24 (
Cloudstrap.Localization). - No automatic
RequireAuthorization()on mapped controllers — protection is the auth package's fallback policy or your attributes. - No missing-cache startup surprise: without a registered
IDistributedCache, the in-memory fallback simply applies (single-instance semantics) instead of failing at startup.
| 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
- AspNetCore.HealthChecks.Uris (>= 9.0.0)
- Azure.Extensions.AspNetCore.Configuration.Secrets (>= 1.5.1)
- Azure.Extensions.AspNetCore.DataProtection.Blobs (>= 1.5.3)
- Azure.Extensions.AspNetCore.DataProtection.Keys (>= 1.6.3)
- Azure.Identity (>= 1.21.0)
- Azure.Storage.Blobs (>= 12.29.1)
- Cloudstrap.Core (>= 0.2.0-preview.83)
- Cloudstrap.Extensions (>= 0.2.0-preview.83)
- Cloudstrap.Observability (>= 0.2.0-preview.83)
- OpenTelemetry.Exporter.Console (>= 1.17.0)
- OpenTelemetry.Exporter.OpenTelemetryProtocol (>= 1.17.0)
- OpenTelemetry.Extensions.Hosting (>= 1.17.0)
- OpenTelemetry.Instrumentation.AspNetCore (>= 1.17.0)
- OpenTelemetry.Instrumentation.Http (>= 1.17.0)
- OpenTelemetry.Instrumentation.Runtime (>= 1.17.0)
- OpenTelemetry.Instrumentation.SqlClient (>= 1.17.0)
- Serilog (>= 4.4.0)
- Serilog.Extensions.Hosting (>= 10.0.0)
- Serilog.Sinks.Console (>= 6.1.1)
- Serilog.Sinks.File (>= 7.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.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.2.0-preview.83 | 40 | 9/3/2026 |
| 0.2.0-preview.2 | 55 | 8/27/2026 |