Shiny.Net.HttpServer.Mediator 1.5.0-beta.1

Prefix Reserved
This is a prerelease version of Shiny.Net.HttpServer.Mediator.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package Shiny.Net.HttpServer.Mediator --version 1.5.0-beta.1
                    
NuGet\Install-Package Shiny.Net.HttpServer.Mediator -Version 1.5.0-beta.1
                    
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="Shiny.Net.HttpServer.Mediator" Version="1.5.0-beta.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Shiny.Net.HttpServer.Mediator" Version="1.5.0-beta.1" />
                    
Directory.Packages.props
<PackageReference Include="Shiny.Net.HttpServer.Mediator" />
                    
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 Shiny.Net.HttpServer.Mediator --version 1.5.0-beta.1
                    
#r "nuget: Shiny.Net.HttpServer.Mediator, 1.5.0-beta.1"
                    
#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 Shiny.Net.HttpServer.Mediator@1.5.0-beta.1
                    
#: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=Shiny.Net.HttpServer.Mediator&version=1.5.0-beta.1&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Shiny.Net.HttpServer.Mediator&version=1.5.0-beta.1&prerelease
                    
Install as a Cake Tool

Build NuGet

Shiny HTTP Server

ASP.NET Core is heavyweight and does not run on .NET MAUI or in several embedded server scenarios. This is a dependency-light, fully AOT/trim-clean HTTP/1.1, HTTP/2 & HTTP/3 server that runs anywhere .NET runs — including .NET MAUI and native tvOS — plus tunnelling so a server embedded in a phone app is reachable from the public internet.

Only Microsoft.Extensions.* abstractions are taken as dependencies. Everything else — JSON, crypto, JWT, OpenAPI, HPACK, QPACK — is built on what is in the box.

Packages

Package Description
Shiny.Net.HttpServer The server: HTTP/1.1, HTTP/2 & HTTP/3, routing, middleware, DI scopes, static files, WebSockets, SSE, sessions, OpenAPI, CORS, rate limiting, IP filtering, host filtering, request localization, webhook signature verification, tunnelling. Includes the typed-endpoint source generator
Shiny.Net.HttpServer.Jwt JWT authentication on in-box crypto — no Microsoft.IdentityModel dependency
Shiny.Net.HttpServer.Acme Automatic HTTPS from Let's Encrypt, ZeroSSL or any ACME CA — HTTP-01 and TLS-ALPN-01 answered by the server itself, account and certificate stored owner-only, renewed on schedule (or when the CA's ARI says) and hot-swapped into the running server with no restart. In-box crypto only; for hosts with public DNS, not phones
Shiny.Net.HttpServer.AzureRelay Azure Relay tunnel provider
Shiny.Net.HttpServer.Ssh SSH remote-forwarding tunnel provider, including zero-account quick tunnels
Shiny.Net.HttpServer.Proxy A reverse proxy — destination clusters, load balancing, active and passive health checks, session affinity, a transform pipeline, WebSocket and HTTP upgrade forwarding, and routes read from IConfiguration with hot reload
Shiny.Net.HttpServer.Mcp Model Context Protocol (Streamable HTTP) transport — host an MCP server without ASP.NET Core, including inside a MAUI app
Shiny.Net.HttpServer.Mediator Publishes Shiny.Mediator requests, commands and streams as endpoints generated at compile time. Generator included
Shiny.Net.HttpServer.DocumentDb Publishes a Shiny.DocumentDb type as a REST resource — list, by-id, count, CRUD, merge-patch or JSON Patch and a live SSE tail
Shiny.Net.HttpServer.WebDav A WebDAV (RFC 4918) class 1 & 2 server over a directory — mount an app's storage in Finder, Windows Explorer or any WebDAV client, and open the same URL in a browser for a file manager with upload, rename and delete
Shiny.Net.HttpServer.CalDav CalDAV (RFC 4791) and CardDAV (RFC 6352) on top of the WebDAV package: serve an app's calendars and contacts so iOS and macOS Calendar and Contacts, Thunderbird and DAVx⁵ can discover, subscribe and sync. Supports well-known discovery, sync-collection, queries with recurrence-aware time ranges, and a directory-backed store or your own ICalendarStore / IAddressBookStore
Shiny.Net.HttpServer.Grpc gRPC and gRPC-Web — unary, streaming and bidirectional methods over the same HTTP/2 stack, with serialization you supply
Shiny.Net.HttpServer.Discovery mDNS/DNS-SD (Bonjour) — advertises the server on the local link and finds the ones other devices advertise, so nobody has to type an IP address. The advertisement is held through a restart rather than blinking out and back, and a registration the responder refuses is retried before it is reported
Shiny.Net.HttpServer.Mobile Mobile lifecycle on Shiny.Core — stop on background and start on resume, an Android foreground service that follows the server's own running state to keep serving, an iOS resume that restarts the server the suspension took, rebind when the device changes network with a bounded retry for the bind a half-up network refuses, and a check for the manifest or bundle entries that silently break local networking. iOS and Android, with or without MAUI
Shiny.Net.HttpServer.Testing An HttpClient wired to the server through memory — endpoint tests with no port, no listener and no socket, but the real parser, router and middleware
Shiny.Net.HttpServer.Tunnels Agent-backed tunnels — supervises cloudflared, ngrok or tailscale and reports the public URL. Desktop, server and CLI. iOS and tvOS forbid process creation, so the agents throw there with a message pointing at the SSH provider or the relay
Shiny.Net.HttpServer.OAuthLoopback The OAuth 2.0 / OpenID Connect loopback redirect receiver (RFC 8252). A desktop app or CLI signs in through the system browser, the way VS Code and gh auth login do, on an ephemeral 127.0.0.1 port. It validates state, accepts form_post, times out and shows a completion page, and it replaces HttpListener. PKCE and the token exchange stay with your OAuth client. Desktop only
Shiny.Net.HttpServer.Tus Resumable uploads over the tus 1.0.0 protocol — a phone upload that drops half way resumes from the last byte instead of restarting; works with tus-js-client, Uppy and TusDotNetClient
Shiny.Net.HttpServer.CommandLine A .NET tool — shinyhttpserver — that serves a directory over WebDAV, so one address is both a browser file manager (browse, upload, rename, delete) and a drive Finder or Explorer can mount, with basic auth, per-operation permissions, and a QR code in the banner so a phone can scan its way in — --tunnel swaps the LAN address for a public pinggy.io tunnel so the phone need not be on the same network. In a terminal it opens a dashboard: live requests (clearable), uploads and downloads in progress, and a settings form that changes the tunnel, HTTPS, port, users and permissions on the running server (--no-tui for the plain banner)

Getting Started

var server = new HttpServer(new HttpServerOptions { Port = 8080 });
server.MapGet("/ping", ctx => ctx.Response.WriteAsync("pong"));
await server.RunAsync();

Every registration this library owns hangs off one builder, in both hosting shapes:

var builder = HttpServer.CreateBuilder();
builder.Options.Port = 8080;
builder.AddAuthentication().AddJwtBearer(o => { o.Issuer = "app"; o.Audience = "app"; o.SigningKey = key; });
builder.AddRateLimiter(o => o.GlobalPolicy = new FixedWindowRateLimitPolicy(100, TimeSpan.FromMinutes(1)));
builder.AddHealthChecks().AddServerCheck();

var app = builder.Build();

// …or, inside an app that already owns a container — the same calls:
services.AddShinyHttpServer(http =>
{
    http.Options.Port = 8080;
    http.AddHealthChecks().AddServerCheck();
    http.Configure(server => server.MapMyAppEndpoints());
});

Typed endpoints, generated at compile time:

[Route("/api/users")]
public class UserEndpoints(IUserService users, ILogger<UserEndpoints> logger)
{
    [Get("/{id:int}")]
    public async Task<IActionResult> GetUser(int id, CancellationToken ct)
        => await users.FindAsync(id, ct) is { } u ? new OkObjectResult(u) : new NotFoundResult();
}

app.MapMyAppEndpoints();   // emitted for every [Route] class in the assembly
app.MapGroup("/v2", api => api.MapMyAppEndpoints());   // or mounted under a prefix

An MCP server, on the same host, reachable from a MAUI app:

builder.Services
    .AddMcpServer(o => o.ServerInfo = new() { Name = "thermostat", Version = "1.0.0" })
    .WithTools<ThermostatTools>()
    .WithHttpTransport();

var app = builder.Build();
app.MapMcp();              // POST/GET/DELETE/OPTIONS on /mcp

The MCP package is trim- and AOT-clean like the rest, with one thing the compiler cannot check for you: a tool's parameter and return types are published as a JSON schema, and building that schema by reflection does not survive trimming. Tools that trade only in primitives need nothing extra; give the rest a source-generated context, and MapMcp() will tell you if you missed one.

[JsonSerializable(typeof(Query))]
[JsonSerializable(typeof(IReadOnlyList<Reading>))]
public partial class ToolJson : JsonSerializerContext;

.WithTools<ThermostatTools>(ToolJson.Default.Options)

On a phone, where the server has to be found and has to survive the device moving:

builder.Services.AddShinyHttpServer(
    http =>
    {
        http.Options.Address = IPAddress.Any;

        // Keeps serving in the background on Android through a foreground service; on iOS, where
        // nothing can, restores the server on resume if it was running. Both rebind on a network change.
        http.AddHttpServerLifecycle(o => o.BackgroundMode = BackgroundServerMode.KeepAlive);

        // Advertises on the local link, so the other device does not need an IP address.
        http.AddHttpServerAdvertisement(o => o.ServiceType = "_myapp._tcp");
    },
    autoStart: false
);

and on the other device:

var found = await locator.FindFirstAsync("_myapp._tcp");
using var client = new HttpClient { BaseAddress = found!.BaseAddress };

What is in the box

The four tiers — one delegate, raw routes, middleware, and source-generated typed endpoints. Each is built on the one below and they compose in the same app.

Core Routing with constraints, runtime-mutable routes and API versioning (URL segment, query, header or media type, with deprecation and sunset headers), ASP.NET-shaped middleware that can read and rewrite both bodies of an exchange, a real IServiceScope per request, results in both Results.* and IActionResult spellings, RFC 9457 problem details and an exception-handler chain, per-endpoint request timeouts, Idempotency-Key handling (draft-ietf-httpapi-idempotency-key-header) so a retried POST gets its stored response instead of running twice, request localization from the query string, a cookie or Accept-Language, RFC 6902 JSON Patch over RFC 6901 JSON Pointer — applied all-or-nothing, bound as a typed endpoint parameter, and failing as problem details that name the operation
Caching Conditional requests for handlers that are not serving a file — If-Match, If-None-Match, If-Modified-Since, 304 and 412 — plus output caching with a bounded in-memory store, where the saving is battery rather than bandwidth
Diagnostics Health checks with liveness/readiness tags, telemetry on the in-box primitives — one Activity per request continuing the caller's traceparent, and the OpenTelemetry HTTP metrics an ASP.NET dashboard already reads — and W3C access logs, rolled and pruned, written off the request path
Formats Content negotiation in both directions — responses chosen from Accept, request bodies from Content-Type. JSON out of the box; XML, MessagePack and protobuf are one line each, and a format of your own is an IOutputFormatter/IInputFormatter pair. XML and MessagePack need no dependency and no attributes on your DTOs: they read the same JsonTypeInfo the JSON path reads, which is what keeps them AOT-clean where XmlSerializer cannot be
Protocols HTTP/1.1, HTTP/2 (own HPACK), HTTP/3 (own QPACK), WebSockets, Server-Sent Events, trailing headers on all three versions, 103 Early Hints and other 1xx interim responses on all three. Never guessed — ALPN over TLS, connection preface over cleartext. WebSockets carry permessage-deflate, keepalive pings, and a registry for broadcasting to a group
Content Static files from disk, embedded resources or a zip archive (on disk or embedded), a published Blazor WebAssembly app, streaming multipart uploads, downloads with byte ranges and conditional GETs, a file browser over a directory, and brotli/gzip/deflate compression in both directions, and RFC 9530 Content-Digest/Repr-Digest verified on uploads as they stream and sent on responses as a header or a trailer
Security Authentication and authorization split ASP.NET-style, with Basic, API key, cookie and JWT schemes; policies, roles and claims; CORS, rate limiting and IP filtering, all with per-endpoint policies; host filtering against DNS rebinding; webhook receivers that verify GitHub, Stripe, Slack, Standard Webhooks and generic HMAC signatures over the raw body, with replay protection, duplicate suppression and key rotation, plus a signer for outgoing webhooks; signed double-submit antiforgery, the browser security headers, HSTS and an HTTPS redirect
TLS Several endpoints with per-endpoint TLS, self-signed certificates generated in managed code (iOS and Android included), client certificates, and SPKI pinning for the app's own HttpClient; the PROXY protocol (v1 and v2) per endpoint, so the real client behind a TCP load balancer reaches the IP filter, rate limiter and logs; and publicly trusted certificates issued and renewed automatically over ACME (Let's Encrypt, ZeroSSL) and hot-swapped with no restart
OpenAPI An OpenAPI 3.0.3 document built entirely from compile-time metadata and your JsonSerializerContext — no reflection, no document object model — one document per API version, and a Scalar API reference page that the browser loads from the CDN, so the app ships no UI
Tunnelling A pluggable ITunnelProvider, the reference relay (both ends), SSH remote forwarding, zero-account quick tunnels, and Azure Relay
Proxy A reverse proxy that goes further than a forwarded route: destination clusters with five load-balancing policies, active probes and passive failure tracking that take a bad instance out of rotation, cookie or header session affinity, a composable transform pipeline for paths, queries and headers in both directions, WebSocket and HTTP upgrade forwarding, and routes read from IConfiguration and reloaded onto the running server without dropping the routes that did not change
Mediator Shiny.Mediator handlers published as endpoints — requests as JSON, commands as a status code, stream requests as Server-Sent Events, all bound at compile time
DocumentDb A document type as a complete HTTP resource, with filtering, cursor paging, sparse fieldsets, ETag/If-Match, RFC 7396 merge patch or RFC 6902 JSON Patch, a live SSE tail, and server-side scopes enforced on both sides of a write
gRPC Unary, client-streaming, server-streaming and bidirectional methods, deadlines, per-message compression and status in trailers — plus gRPC-Web for browsers and anything on HTTP/1.1. Marshalling is yours, so nothing reflects over your messages
WebDAV RFC 4918 classes 1 and 2 over a directory — or over anything an IWebDavFileSystem describes — PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK/UNLOCK, the If header and dead properties — so an app's storage mounts as a drive with no client to write
CalDAV & CardDAV Calendars and contacts over RFC 4791 / 6352: /.well-known discovery, principals per signed-in user, MKCALENDAR, validated PUT with no-uid-conflict and ETag preconditions, calendar-query / addressbook-query / multiget / free-busy / sync-collection — so the phone's own Calendar and Contacts apps sync with your app
Resumable uploads tus 1.0.0 core plus creation, creation-with-upload, defer-length, termination, expiration, checksum and concatenation — streamed to a pluggable store, bytes from an interrupted request kept, offsets durable across restarts
Lifecycle Start, stop and restart at runtime, serialized and idempotent, with an observable state — an embedded server gets toggled, not just booted. It also follows the device: rebinding when the addresses change, and following the app between foreground and background
Resilience Every state change says why it happened and carries the exception behind it, and a server that stops serving never does it quietly. A listener that dies underneath a running server is logged, reported and rebound; a transient accept failure is retried with backoff; a restart or a rebind whose bind is refused keeps trying and, if it never succeeds, says so unmistakably rather than leaving a server that claims to be running with nothing behind it. On by default — an app that has to opt in to not-silently-dying will not have opted in
Sign-in The loopback half of an OAuth / OpenID Connect sign-in from a desktop app or CLI. It opens the system browser, receives the redirect on an ephemeral 127.0.0.1 port and checks state. The code is handed to whichever OAuth client you already use, and the user is told to return to the app
Discovery The other half of hosting on a phone. mDNS advertises the server as the device moves and withdraws it when the server stops — telling a restart apart from a stop, so peers are not made to re-resolve a service that never went away — and a publication the responder refuses is retried rather than leaving an app that runs perfectly and is found by nobody; the locator turns what is on the link into a base address a client can call
Testing An in-memory transport, so an endpoint test costs no port and leaks no listener while still going through the real parser, router, middleware and framing

Everything shipping targets net10.0 with the trim, AOT and single-file analyzers enabled, so "AOT-clean" is enforced by the build rather than claimed in a readme.

Documentation

Full docs are at shinylib.net/httpserver.

Support

Shiny is free and will continue to be, but maintenance and support take a heavy toll on sustainability. If you or your company have the resources, please consider becoming a GitHub Sponsor.

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.

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
2.0.0-beta.3 0 9/29/2026
2.0.0-beta.2 0 9/29/2026
2.0.0-beta.1 0 9/29/2026
1.5.0-beta.1 0 9/28/2026
1.4.0 52 9/23/2026
1.3.0 102 9/22/2026
1.3.0-g2e9cb54e84 71 9/22/2026
1.2.2 93 9/17/2026
1.2.2-g9365e2a6a1 80 9/17/2026
1.2.1 99 9/17/2026
1.2.1-gabba9af692 88 9/17/2026
1.2.0 113 9/16/2026
1.2.0-g437801aa7b 87 9/16/2026
1.1.1 108 9/5/2026
1.1.1-g75f7ad4146 102 9/5/2026
1.1.1-g4aeff4ea38 95 9/7/2026
1.0.5 133 8/30/2026
1.0.5-g1ae616228f 104 8/30/2026
1.0.4 107 8/27/2026
1.0.4-g253ed724e7 103 8/27/2026
Loading failed