CosmoApiServer.Core
3.2.3
dotnet add package CosmoApiServer.Core --version 3.2.3
NuGet\Install-Package CosmoApiServer.Core -Version 3.2.3
<PackageReference Include="CosmoApiServer.Core" Version="3.2.3" />
<PackageVersion Include="CosmoApiServer.Core" Version="3.2.3" />
<PackageReference Include="CosmoApiServer.Core" />
paket add CosmoApiServer.Core --version 3.2.3
#r "nuget: CosmoApiServer.Core, 3.2.3"
#:package CosmoApiServer.Core@3.2.3
#addin nuget:?package=CosmoApiServer.Core&version=3.2.3
#tool nuget:?package=CosmoApiServer.Core&version=3.2.3
CosmoApiServer
A .NET HTTP server built on System.IO.Pipelines and System.Net.Sockets with support for HTTP/1.1, HTTP/2, and HTTP/3 over QUIC. Includes a middleware pipeline, routing, frontend hosting, and real-time primitives.
Contents
- Protocols
- Quick Start
- Frontend Integration
- Real-time
- Security
- Middleware & Pipeline
- Caching
- Diagnostics & Observability
- Razor Components
- Samples
- Benchmarks
- Deployment
- Changelog
Protocols
| Protocol | Support |
|---|---|
| HTTP/1.1 | Keep-alive, pipelining |
| HTTP/2 | h2c cleartext + ALPN over TLS |
| HTTP/3 | QUIC via MsQuic (Windows) and Network.framework (macOS). Request/response trailers, streamed bodies, NDJSON streaming, QPACK, graceful GOAWAY. |
| TLS | SslStream with ALPN (h2 / http/1.1) |
var builder = CosmoWebApplicationBuilder.Create()
.ListenOn(9092)
.UseHttps("cert.pfx", "password")
.UseHttp3();
Quick Start
# Minimal API server
var builder = CosmoWebApplicationBuilder.Create().ListenOn(9092);
var app = builder.Build();
app.MapGet("/health", ctx => {
ctx.Response.WriteJson(new { status = "ok" });
return ValueTask.CompletedTask;
});
app.Run();
Frontend Integration
All framework integrations share the same three-layer structure:
| Layer | Purpose | Method |
|---|---|---|
| Dev server | Spawn and manage the frontend process | UseViteDevServer / UseAngularDevServer / UseNextDevServer |
| Dev proxy | Forward framework module paths to the dev server | UseViteDevProxy / UseReactDevProxy / UseNextDevProxy / UseAngularDevProxy |
| Production | Serve the built output with compression + SPA fallback | UseStaticFrontend (or framework-specific wrapper) |
Nuxt / Vite Dev Mode
UseViteDevServer spawns the frontend dev process as a managed IHostedService, blocking server startup until it is ready. UseViteDevProxy forwards Vite module-graph paths to the dev server so the browser can use a single origin.
builder.UseViteDevServer(o =>
{
o.WorkingDirectory = "frontend";
o.Command = "npm";
o.Arguments = "run dev";
o.ReadyPattern = "Local:";
o.ReadyTimeout = TimeSpan.FromSeconds(45);
o.LogPrefix = "[nuxt]";
});
builder.UseViteDevProxy(o =>
{
o.DevServerUrl = "http://127.0.0.1:3000";
o.ProxiedPrefixes = ["/@vite", "/@fs", "/@id", "/_nuxt", "/__nuxt", "/__vite_ping"];
});
The ViteDevServerService shuts down the child process tree (Kill(entireProcessTree: true)) when the host stops, freeing the dev port cleanly.
Nuxt SSR with server-side API calls (nuxt-auth-utils, useFetch in SSR context)
When Nuxt uses SSR and makes API calls during its startup warmup (e.g. session checks via nuxt-auth-utils), set ReadyPattern = null. This lets the .NET HTTP listener open immediately so the backend is reachable when Nuxt's warmup fires. Without this, the default blocking behaviour delays the listener until after Nuxt is ready — causing ECONNREFUSED during warmup.
builder.UseViteDevServer(o =>
{
o.WorkingDirectory = "frontend";
o.Command = "npm";
o.Arguments = $"exec nuxt dev -- --host 127.0.0.1 --port 3000";
o.ReadyPattern = null; // .NET opens immediately; Nuxt starts in background
o.LogPrefix = "[nuxt]";
o.Environment["NUXT_SESSION_PASSWORD"] = "...";
o.Environment["API_BASE"] = "http://127.0.0.1:9183";
});
// For SSR projects UseReverseProxy forwards page requests; UseNuxtIntegrated is for SPA/static only
builder.UseViteDevProxy(o => o.DevServerUrl = "http://127.0.0.1:3000");
builder.UseReverseProxy(o => o.Routes.Add(new ProxyRoute
{
PathPrefix = "/",
Destination = "http://127.0.0.1:3000",
ExcludedPrefixes = ["/api"]
}));
Nuxt Integrated Production
Serves a pre-built Nuxt SPA from .output/public with tiered cache headers, Brotli/GZip compression, and SPA fallback.
builder.UseNuxtIntegrated(
outputPath: "frontend/.output/public",
configureFallback: o => o.ExcludedPrefixes = ["/api", "/health"]);
Vue / Vite Production
builder.UseViteFrontend(o =>
{
o.HtmlTemplatePath = "frontend/index.html";
o.ManifestPath = "wwwroot/.vite/manifest.json";
o.ExcludedPrefixes = ["/api", "/health"];
});
// With server-provided initial state
builder.UseViteFrontend(o =>
{
o.RenderAsync = ctx => ValueTask.FromResult<ViteRenderResult?>(new ViteRenderResult
{
HeadHtml = "<title>Dashboard</title>",
InitialState = new { user = "alice", route = ctx.HttpContext.Request.Path }
});
});
Content Security Policy
Generates a per-request nonce and injects it into inline scripts emitted by ViteFrontendMiddleware.
builder.UseCsp(o =>
{
o.DefaultSrc = ["'self'"];
o.ScriptSrc = ["'self'", "'nonce-{nonce}'"];
o.StyleSrc = ["'self'", "'unsafe-inline'"];
o.ConnectSrc = ["'self'"];
o.ImgSrc = ["'self'", "data:"];
});
React + Vite
Dev mode — Vite runs on port 5173 by default:
builder.UseViteDevServer(o =>
{
o.WorkingDirectory = "frontend";
o.Command = "npm";
o.Arguments = "run dev";
o.ReadyPattern = "Local:";
o.LogPrefix = "[react]";
});
builder.UseReactDevProxy(); // proxies /@vite, /@fs, /@id, /@react-refresh
builder.UseViteFrontend(o =>
{
o.EntryName = "src/main.tsx";
o.DevServerUrl = "http://127.0.0.1:5173";
o.ExcludedPrefixes = ["/api", "/health"];
});
Production — vite build outputs to dist/ with a manifest:
builder.UseViteFrontend(o =>
{
o.ManifestPath = "frontend/dist/.vite/manifest.json";
o.HtmlTemplatePath = "frontend/index.html";
o.EntryName = "src/main.tsx";
o.ExcludedPrefixes = ["/api", "/health"];
});
Angular
Dev mode — Angular CLI doesn't use Vite, so all traffic is reverse-proxied:
builder.UseAngularDevServer(o =>
{
o.WorkingDirectory = "frontend";
// defaults: npx ng serve --host 127.0.0.1, ready pattern "Application bundle generation complete"
});
builder.UseAngularDevProxy(); // reverse-proxies / → http://127.0.0.1:4200
Production — ng build outputs to dist/<project>/browser/:
builder.UseAngularFrontend(
outputPath: "frontend/dist/my-app/browser",
configureFallback: o => o.ExcludedPrefixes = ["/api", "/health"]);
Next.js
Dev mode — Next.js uses its own HMR paths:
builder.UseNextDevServer(o =>
{
o.WorkingDirectory = "frontend";
// defaults: npm run dev, ready pattern "Ready"
});
builder.UseNextDevProxy(); // proxies /__next, /_next, /webpack-hmr
builder.UseViteFrontend(o =>
{
o.DevServerUrl = "http://127.0.0.1:3000";
o.ExcludedPrefixes = ["/api", "/health"];
});
Production (static export) — add output: 'export' to next.config.js, then next build outputs to out/:
builder.UseNextStaticExport(
outputPath: "frontend/out",
configureFallback: o => o.ExcludedPrefixes = ["/api", "/health"]);
Production (SSR) — proxy all non-API traffic to next start:
builder.UseReverseProxy(o =>
o.Routes.Add(new ProxyRoute
{
PathPrefix = "/",
Destination = "http://127.0.0.1:3000",
ExcludedPrefixes = ["/api", "/health"]
}));
SvelteKit
Dev mode — SvelteKit uses Vite:
builder.UseViteDevServer(o =>
{
o.WorkingDirectory = "frontend";
o.Command = "npm";
o.Arguments = "run dev";
o.ReadyPattern = "Local:";
o.LogPrefix = "[svelte]";
});
builder.UseViteDevProxy(o =>
{
o.DevServerUrl = "http://127.0.0.1:5173";
o.ProxiedPrefixes = ["/@vite", "/@fs", "/@id", "/@svelte-kit"];
});
Production (adapter-static) — vite build outputs to build/:
builder.UseSvelteKitStatic(
outputPath: "frontend/build",
configureFallback: o => o.ExcludedPrefixes = ["/api", "/health"]);
Production (adapter-node) — proxy to the Node server:
builder.UseReverseProxy(o =>
o.Routes.Add(new ProxyRoute
{
PathPrefix = "/",
Destination = "http://127.0.0.1:3000",
ExcludedPrefixes = ["/api", "/health"]
}));
Blazor WebAssembly
Blazor WASM runs entirely in the browser — the .NET runtime and your assemblies are compiled to WebAssembly and downloaded once. CosmoApiServer hosts the published output as static files with two additions over a plain SPA:
application/wasmMIME type — browsers reject WASM modules served asapplication/octet-stream- Pre-compressed
_framework/file serving — Blazor's publish pipeline emits.brand.gzvariants of every framework file. Streaming these directly (withContent-Encoding: br) is far faster than re-compressingdotnet.native.wasm(30–60 MB) on every request
Setup
- Publish your Blazor WASM project to the
blazor/wwwrootfolder of your CosmoApiServer project:
dotnet publish BlazorApp/BlazorApp.csproj -c Release -o blazor
- Register the middleware:
builder.UseBlazorWasm(
outputPath: "blazor/wwwroot",
configureFallback: o => o.ExcludedPrefixes = ["/api"]);
The SPA fallback returns index.html for all routes not matched by the API, enabling Blazor's client-side router.
Project structure
Keep the Blazor client project in a subdirectory (e.g. BlazorClient/) of the server project. Because Microsoft.NET.Sdk includes all *.cs files recursively by default, you must exclude the client's source files from the server build:
<ItemGroup>
<Compile Remove="BlazorClient\**\*.cs" />
</ItemGroup>
Without this, the server compiler picks up Blazor client code (e.g. WebAssemblyHostBuilder) and fails with CS0234.
Co-hosting API + Blazor WASM
var app = builder.Build();
app.MapGet("/api/weather", ctx => { ... });
// Blazor WASM handles everything else
Blazor calls your API endpoints the same way any SPA would — using HttpClient with a base address pointing at the same origin.
Dev proxy paths by framework
| Framework | Dev server default port | Paths to proxy |
|---|---|---|
| Nuxt | 3000 | /@vite /@fs /@id /_nuxt /__nuxt /__vite_ping |
| React + Vite | 5173 | /@vite /@fs /@id /@react-refresh |
| SvelteKit | 5173 | /@vite /@fs /@id /@svelte-kit |
| Next.js | 3000 | /__next /_next /__nextjs_original-stack-frame /webpack-hmr |
| Angular | 4200 | Full reverse proxy (no Vite module graph) |
Reverse Proxy
builder.UseReverseProxy(o =>
o.Routes.Add(new ProxyRoute
{
PathPrefix = "/",
Destination = "http://127.0.0.1:3000",
ExcludedPrefixes = ["/api", "/health"]
}));
Real-time
Server-Sent Events
MapSse sets text/event-stream headers and calls BeginSseAsync automatically.
app.MapSse("/api/live/metrics", async ctx =>
{
using var timer = new PeriodicTimer(TimeSpan.FromSeconds(1));
while (!ctx.RequestAborted.IsCancellationRequested &&
await timer.WaitForNextTickAsync(ctx.RequestAborted))
{
var json = JsonSerializer.Serialize(new { cpu = 42.1, memory = 68.3 });
await ctx.Response.WriteSseAsync(json, eventName: "metric",
cancellationToken: ctx.RequestAborted);
}
});
Heartbeat helper prevents proxies from closing idle connections:
var heartbeat = ctx.Response.SendSseHeartbeatsAsync(TimeSpan.FromSeconds(15), ctx.RequestAborted);
// ... event loop ...
await heartbeat;
SignalR
var builder = CosmoWebApplicationBuilder.Create().AddSignalR();
var app = builder.Build();
app.MapHub<ChatHub>("/chat");
public sealed class ChatHub : Hub
{
public async Task SendMessage(string user, string message) =>
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
Supports JSON and MessagePack protocols, groups, server-push via IHubContext<T>, server streaming, cancellation, and reconnect-after-restart. Compatible with standard ASP.NET SignalR clients.
gRPC
var builder = CosmoWebApplicationBuilder.Create().AddGrpc();
var app = builder.Build();
app.MapGrpcService<GreeterService>();
public sealed class GreeterService : GrpcServiceBase, IGrpcServiceDescriptor
{
public IReadOnlyList<GrpcMethodDescriptor> Methods =>
[
new GrpcMethodDescriptor("Greeter", "SayHello", GrpcMethodType.Unary, typeof(GreeterService),
async (svc, ctx, ct) =>
{
var req = await ctx.ReadRequestAsync<HelloRequest>(ct);
await ctx.WriteResponseAsync(new HelloReply { Message = $"Hello {req.Name}" }, ct);
})
];
}
Supports unary and server-streaming. Uses standard 5-byte gRPC framing.
Security
JWT / OAuth / OIDC
builder
.UseJwtAuthentication()
.UseOAuthAuthentication() // JWKS discovery
.AddAuthorization();
Antiforgery
builder.AddAntiforgery();
// ...
app.UseAntiforgery();
app.MapGet("/form", ctx =>
{
var svc = ctx.RequestServices.GetRequiredService<IAntiforgeryService>();
var tokens = svc.GetAndStoreTokens(ctx);
return TypedResults.Text($"<input name='__RequestVerificationToken' value='{tokens.RequestToken}' />");
});
Rate Limiting
Fixed-window per-IP limiter with X-Forwarded-For support:
builder.UseRateLimiting(opts =>
{
opts.Limit = 200;
opts.Window = TimeSpan.FromMinutes(1);
opts.StatusCode = 429;
opts.TrustProxy = true;
});
Middleware & Pipeline
Request
↓ GlobalExceptionHandlerMiddleware
↓ CorsMiddleware
↓ CspMiddleware
↓ ViteDevProxyMiddleware (dev)
↓ ViteFrontendMiddleware (dev) / NuxtIntegratedMiddleware (prod)
↓ RouterMiddleware
Registration follows a builder pattern:
var builder = CosmoWebApplicationBuilder.Create()
.ListenOn(9092)
.UseLogging()
.UseExceptionHandler()
.UseCors(o => { o.AllowAnyOrigin(); o.AllowAnyMethod(); o.AllowAnyHeader(); })
.UseSession(new SessionOptions { IdleTimeout = TimeSpan.FromMinutes(20) })
.UseRequestTimeouts(new RequestTimeoutOptions { DefaultTimeout = TimeSpan.FromSeconds(30) })
.UseRateLimiting(opts => { opts.Limit = 100; opts.Window = TimeSpan.FromMinutes(1); })
.UseForwardedHeaders()
.AddOutputCache()
.AddHealthChecks();
Routing
app.MapGet("/items/{id}", ctx => { ... });
app.MapPost("/items", ctx => { ... });
// Typed results
app.MapGet("/items/{id}", ctx =>
id is null ? TypedResults.NotFound() : TypedResults.Ok(new { id, name = "Widget" }));
Exception Handling
builder
.AddExceptionHandler<ValidationExceptionHandler>()
.AddExceptionHandler<DatabaseExceptionHandler>();
public sealed class ValidationExceptionHandler : IExceptionHandler
{
public async ValueTask<bool> TryHandleAsync(HttpContext ctx, Exception ex, CancellationToken ct)
{
if (ex is not ValidationException vex) return false;
ctx.Response.StatusCode = 422;
await ctx.Response.WriteJsonAsync(new { errors = vex.Errors }, ct);
return true;
}
}
Scheduling
builder.AddScheduler();
// ...
app.UseScheduler(scheduler =>
{
scheduler.Schedule(() => Console.WriteLine("tick")).EveryMinute();
scheduler.ScheduleAsync(async () => await SyncInvoices()).Cron("0 */1 * * *");
scheduler.Schedule<CleanupJob>().DailyAt(2, 30);
});
Caching
Output Cache
builder.AddOutputCache();
// ...
app.UseOutputCaching();
var policy = OutputCachePolicy.Build()
.Expire(TimeSpan.FromMinutes(5))
.VaryByQuery("page", "sort")
.Tag("products")
.ToPolicy();
app.MapGet("/products", async ctx =>
{
ctx.SetOutputCachePolicy(policy);
await ctx.Response.WriteJsonAsync(GetProducts());
});
// Tag-based invalidation
var store = ctx.RequestServices.GetRequiredService<IOutputCacheStore>();
await store.EvictByTagAsync("products");
Response Cache (ETag / 304)
builder.UseResponseCaching();
// Handlers set ctx.Response.ETag; returns 304 when If-None-Match matches.
Memory & Distributed Cache
builder
.AddMemoryCache()
.AddDistributedMemoryCache();
Diagnostics & Observability
Health Checks
builder.AddHealthChecks()
.AddCheck("db", () => HealthCheckResult.Healthy("Connected"))
.AddCheck<MyDbHealthCheck>("database");
app.MapHealthChecks("/health");
Problem Details (RFC 7807)
builder.AddProblemDetails();
app.MapGet("/items/{id}", async ctx =>
{
var svc = ctx.RequestServices.GetRequiredService<IProblemDetailsService>();
await svc.WriteAsync(new ProblemDetailsContext
{
HttpContext = ctx,
ProblemDetails = new ProblemDetails { Status = 404, Title = "Not Found" }
});
});
Distributed Tracing
W3C traceparent propagation, OpenTelemetry-compatible ActivitySource:
builder.UseTracing("MyService");
Razor Components
Full .razor support with @page, [Parameter], [CascadingParameter], @inject, @bind, EventCallback, and validation components.
@page "/hello/{Name}"
@inherits Microsoft.AspNetCore.Components.ComponentBase
@inject NavigationManager Nav
<h1>Hello, @Name!</h1>
<p>Path: @Nav.Uri</p>
@code {
[Parameter] public string Name { get; set; }
}
Forms
<EditForm Model="@person" Action="/contact" Method="post">
<InputText Name="name" Value="@person.Name" />
<InputNumber Name="age" Value="@person.Age" />
<InputSelect Name="country" Value="@person.Country">
<option value="us">United States</option>
</InputSelect>
<ValidationMessage For="Name" />
<ValidationSummary />
<button type="submit">Submit</button>
</EditForm>
Change Detection
var ctx = new EditContext(model);
model.Name = "Bob";
ctx.NotifyFieldChanged("Name");
ctx.IsModified("Name"); // true
ctx.GetModifiedFields(); // ["Name"]
ctx.FieldCssClass("Name"); // "modified valid"
ctx.MarkAsUnmodified();
Samples
| Sample | Description |
|---|---|
samples/HelloWorldSample |
Minimal server with a single route |
samples/CosmoKitchenSink |
Covers most backend features in one project |
samples/FeatureShowcase |
Auth, SignalR, gRPC, output cache, and more |
samples/WeatherApp |
REST API with JWT auth, DI, streaming, and SQL |
samples/NuxtUiSample |
Nuxt 4 + Nuxt UI frontend backed by Cosmo APIs |
samples/LiveOpsSample |
Real-time dashboard: SSE, CSP, Vite dev server, Nuxt integrated deployment |
samples/CosmoBlazorSample |
SSR with Razor components |
samples/BlazorWasmSample |
Blazor WebAssembly co-hosted with a CosmoApiServer API |
BlazorWasmSample
cd samples/BlazorWasmSample
./run.sh
Publishes the Blazor WASM client to blazor/wwwroot, then starts the CosmoApiServer backend on http://localhost:5050. Includes Notes (CRUD via /api/notes), Counter, and Weather pages.
LiveOpsSample
cd samples/LiveOpsSample
npm run frontend:install
npm run dev
Benchmarks:
npm run benchmark # API-only latency (no Nuxt)
npm run benchmark:nuxt # Cosmo integrated vs Nuxt Nitro standalone
NuxtUiSample
cd samples/NuxtUiSample
npm run dev
Benchmarks
Single-client sequential HTTP/1.1, connection reused across rounds. 100 warmup + 1000 measured per scenario. All times in milliseconds.
macOS arm64
| Scenario | CosmoApiServer | ASP.NET Core |
|---|---|---|
| GET /ping | P50 0.12ms · 8,600 ops/s | P50 0.14ms · 7,300 ops/s |
| GET /json | P50 0.13ms · 8,400 ops/s | P50 0.18ms · 5,600 ops/s |
| GET /large-json | P50 0.41ms · 2,400 ops/s | P50 0.58ms · 1,700 ops/s |
| POST /echo | P50 0.15ms · 6,500 ops/s | P50 0.20ms · 5,000 ops/s |
| GET /stream | P50 0.22ms · 4,500 ops/s | P50 0.31ms · 3,200 ops/s |
Note: these are single-threaded sequential measurements. Concurrent throughput will differ.
LiveOpsSample API (production mode)
| Scenario | P50 | P99 | ops/sec |
|---|---|---|---|
| GET /ping | 0.12ms | 0.27ms | 8,643 |
| GET /health | 0.13ms | 0.27ms | 7,994 |
| GET /api/status | 0.12ms | 0.27ms | 8,432 |
JSON serialisation of 5 service records (/api/status) adds no measurable latency over a plain text response.
Deployment
HTTP/3 in production
Add UseHttp3() with a valid certificate:
var builder = CosmoWebApplicationBuilder.Create()
.ListenOn(9092)
.UseHttps("cert.pfx", "password")
.UseHttp3();
When running Nuxt through UseNuxtIntegrated, all assets — HTML, JS, CSS — are served by Cosmo over the same QUIC connection. SSE streams benefit from QUIC's per-stream flow control, which avoids head-of-line blocking between concurrent requests.
Cloudflare Pages / Workers
Nuxt can be deployed to Cloudflare using the cloudflare_pages preset:
npx nuxi build --preset=cloudflare_pages
This gives HTTP/3 at the Cloudflare edge automatically. However, there are trade-offs relevant to this architecture:
| Cloudflare | Cosmo + UseHttp3() |
|
|---|---|---|
| HTTP/3 on browser leg | Yes (edge) | Yes (direct) |
| SSE streams | Fragile — 100s connection timeout on free plan | Native |
| API colocation | No — /api/* still needs an origin server |
Yes |
| Cloudflare → origin leg | HTTP/2 at best | N/A |
Cloudflare is suitable for frontends that are mostly static or read-heavy without persistent connections. For SSE-heavy or API-coupled deployments, UseHttp3() on Cosmo keeps the entire stack on one connection and one protocol.
Changelog
v3.2.3
BlazorWasmSample— new sample: Notes CRUD + Counter + Weather, Blazor WASM co-hosted with CosmoApiServerUseBlazorWasmproject structure: document<Compile Remove="BlazorClient\**\*.cs" />requirement when client lives in a subdirectory of the server project
v3.2.2
UseBlazorWasm— hosts published Blazor WebAssembly apps with pre-compressed_framework/file serving andapplication/wasmMIME typeStaticFileMiddleware— added.wasm → application/wasmto the MIME table
v3.2.0
- Frontend integration for React + Vite, Angular, Next.js, and SvelteKit
UseStaticFrontend(outputPath)— generic base for all static SPA deploymentsUseAngularFrontend,UseNextStaticExport,UseSvelteKitStatic— framework-specific wrappersUseReactDevProxy,UseNextDevProxy,UseAngularDevProxy— pre-configured dev proxies per frameworkUseAngularDevServer,UseNextDevServer— pre-configured dev server process management- LiveOpsSample: benchmark scripts (
run-benchmark.sh,run-nuxt-benchmark.sh) - Documentation rewrite — structured, framework-agnostic
v3.1.0
- Server-Sent Events, Content Security Policy, Vite Dev Proxy, Vite Dev Server, Nuxt Integrated, Reverse Proxy
samples/LiveOpsSampledemonstrating all six features- Bug fixes: CORS origin spoofing guard, CSRF path bypass,
Retry-Afteroff-by-one,ForwardedHeaderstrusted-proxy gate,AntiforgeryMiddlewareContent-Type guard, SPA fallback cache-control - 373 tests
v3.0.3
- Vue frontend hosting via
ViteFrontendMiddleware samples/NuxtUiSample
v3.0.2
HtmlEditorComponentfor Razor slices
v3.0.1
- Razor:
InputDate,InputRadioGroup,InputRadio,InputFile,RenderTreeBuilderstubs
v3.0.0
- HTTP/3 production-ready
- Rate Limiting
- H3Interop validation tool (32/32 scenarios)
- Windows benchmark scripts
- 313 tests
v2.1.0 — v2.1.4
- SignalR (JSON + MessagePack), gRPC, Sessions, Request Timeouts, Response Caching, Forwarded Headers, Request Decompression, Distributed Tracing, Endpoint Filters,
IHttpContextAccessor - Output Caching, Antiforgery, TypedResults,
IExceptionHandler,IHostedService, WebSockets
v2.0.5 — v2.0.7
- Health Checks, Problem Details, Policy-Based Authorization, OAuth/OIDC, Memory Cache, Distributed Cache,
IHttpClientFactory - Stream flush coalescing, HTTP/3 QPACK, trailers, GOAWAY
Credits
- Scheduling powered by Coravel
| 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
- Cosmo.Transport (>= 1.0.2)
- Google.Protobuf (>= 3.29.3)
- Microsoft.AspNetCore.SignalR.Protocols.Json (>= 10.0.1)
- Microsoft.AspNetCore.SignalR.Protocols.MessagePack (>= 10.0.1)
- Microsoft.Extensions.Caching.Memory (>= 10.0.1)
- Microsoft.Extensions.Configuration (>= 10.0.1)
- Microsoft.Extensions.Configuration.CommandLine (>= 10.0.1)
- Microsoft.Extensions.Configuration.EnvironmentVariables (>= 10.0.1)
- Microsoft.Extensions.Configuration.Json (>= 10.0.1)
- Microsoft.Extensions.DependencyInjection (>= 10.0.1)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.1)
- Microsoft.Extensions.Http (>= 10.0.1)
- Microsoft.Extensions.Logging (>= 10.0.1)
- Microsoft.IdentityModel.JsonWebTokens (>= 8.16.0)
- System.IdentityModel.Tokens.Jwt (>= 8.16.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on CosmoApiServer.Core:
| Package | Downloads |
|---|---|
|
CosmoS3
Amazon S3-compatible object storage server built on CosmoApiServer.Core. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.2.3 | 24 | 4/12/2026 |
| 3.2.1 | 29 | 4/12/2026 |
| 3.2.0 | 24 | 4/12/2026 |
| 3.1.0 | 31 | 4/12/2026 |
| 3.0.3 | 32 | 4/11/2026 |
| 3.0.2 | 39 | 4/10/2026 |
| 3.0.1 | 78 | 4/9/2026 |
| 3.0.0 | 217 | 4/4/2026 |
| 2.1.4 | 89 | 4/3/2026 |
| 2.1.3 | 85 | 4/3/2026 |
| 2.1.2 | 79 | 4/3/2026 |
| 2.1.1 | 81 | 4/3/2026 |
| 2.1.0 | 81 | 4/3/2026 |
| 2.0.9 | 82 | 4/3/2026 |
| 2.0.8 | 80 | 4/3/2026 |
| 2.0.7 | 90 | 4/3/2026 |
| 2.0.6 | 90 | 4/2/2026 |
| 2.0.5 | 114 | 4/1/2026 |
| 2.0.4 | 81 | 4/1/2026 |
| 2.0.3 | 101 | 3/31/2026 |