Routing & Conventions
Kestrun lets you map routes from scripts (PowerShell, C#, VB, etc.), native delegates, Razor, and static HTML templates. All of these eventually flow through a unified set of conventions:
- Authentication schemes & authorization policies
- CORS policies
- Rate limiting policies
- Anonymous / authenticated access
- Antiforgery disable switches
- Short-circuit metadata (stop further middleware)
- OpenAPI (summary, description, operation id, tags, group)
- Language metadata for discovery / diagnostics
This guide explains how to:
- Map routes using the high-level helpers
- Apply conventions to ad‑hoc endpoints built with
app.MapGet/MapPost - Understand duplicate detection & replacement
- PowerShell parity and current limitations
1. Mapping Routes (Script & Native)
C# minimal example:
var builder = WebApplication.CreateBuilder(args);
var host = builder.Services.AddKestrunHost();
host.AddMapRoute("/hello", HttpVerb.Get, async ctx =>
{
ctx.Response.StatusCode = 200;
await ctx.Response.WriteAsync("Hello native");
}, requireSchemes: new[] { "Bearer" });
host.AddMapRoute(new MapRouteOptions
{
Pattern = "/time",
HttpVerbs = [ HttpVerb.Get ],
Code = "[DateTime]::UtcNow",
Language = ScriptLanguage.PowerShell,
OpenAPI = new() { Summary = "UTC time" },
AllowAnonymous = true,
DisableAntiforgery = true
});
var app = builder.Build();
app.UseKestrun(host);
app.Run();
PowerShell equivalent:
New-KrServer -Name demo
Add-KrEndpoint -Port 5000 -IPAddress ([IPAddress]::Loopback)
Add-KrMapRoute -Pattern '/time' -HttpVerb GET -Code '[DateTime]::UtcNow' -OpenApiSummary 'UTC time' -AllowAnonymous -DisableAntiforgery
Enable-KrConfiguration
Start-KrServer | Out-Null
2. Applying Conventions to Ad‑Hoc Endpoints
If you map endpoints directly with ASP.NET Core (e.g. app.MapGet), you can still apply the same Kestrun conventions using KestrunHost.ApplyKestrunConventions.
var route = app.MapGet("/metrics/raw", () => Results.Ok(new { workers = 7, queue = 12 }));
host.ApplyKestrunConventions(route, opts =>
{
opts.RequirePolicies = new[] { "MetricsViewer" };
opts.RateLimitPolicyName = "default";
opts.DisableAntiforgery = true; // machine-to-machine
opts.AllowAnonymous = false; // enforce auth
opts.ShortCircuit = true;
opts.ShortCircuitStatusCode = 200; // ensure no other middleware runs
opts.OpenAPI.Summary = "Raw internal metrics";
opts.OpenAPI.Tags = ["metrics", "internal"];
});
Notes:
Why no Pattern-Only Overload?
Once a route is built and added to the endpoint data source, its IEndpointConventionBuilder is not retrievable by just the pattern + verb pair. Kestrun keeps logical registration info (MapRouteOptions) for duplicate detection, but not the original mutable builder instance. Because of this, applying conventions post-hoc purely by pattern isn’t reliable (ordering and metadata emission timing become ambiguous). Instead, capture the builder when you map or re-map the route.
If you need to add conventions later:
- Remove (or ignore) the original route.
- Re-map with the desired options.
- Or wrap the underlying handler in your own aggregate.
3. Duplicate Detection & Replacement
AddMapRoute records routes in an internal dictionary keyed by (pattern, method). When you add another route with the same pair:
For health probes, registering a probe with the same name replaces the prior one (log level Information).
4. PowerShell Parity & Limitations
Add-KrMapRoute mirrors the C# helpers for mapping. A PowerShell wrapper for ad‑hoc convention application is not provided yet because PowerShell typically maps routes through the cmdlet itself (thus already invoking the shared convention logic). If you hand-author endpoints in a compiled extension, apply conventions in C#.
If a future scenario requires a PowerShell Apply-KrRouteConventions, the design would need to surface the underlying IEndpointConventionBuilder or perform a re-map. Until then, use the existing route cmdlets or create a tiny .NET helper.
5. OpenAPI Metadata Tips
| Field | When to Use | Effect |
|---|---|---|
OperationId | Client generation / uniqueness | Sets endpoint name (WithName) |
Summary | Brief, 1-line overview | Appears in Swagger list |
Description | Detailed explanation | Expanded operation view |
Tags | Group related endpoints | Supports filtering / UI grouping |
GroupName | Versioning / module grouping | Creates logical doc section |
Only non-empty properties are applied. You can call ApplyKestrunConventions multiple times; later calls can add fields that were missing earlier.
6. Short-Circuiting
Set ShortCircuit = true and ShortCircuitStatusCode (required) to prevent subsequent middleware from executing. This is useful for endpoints like /health, /ready, or fast internal metadata responses.
7. Antiforgery Guidance
Antiforgery is only validated for unsafe verbs (POST/PUT/PATCH/DELETE) and only when DisableAntiforgery is false. Most machine endpoints (health, metrics, diagnostics) disable antiforgery while remaining protected by auth + rate limiting.
8. Troubleshooting
| Symptom | Explanation | Action |
|---|---|---|
| Conventions not applied | Builder not passed through ApplyKestrunConventions | Capture builder variable before chaining |
| Auth scheme error | Scheme not registered | Register scheme before mapping route |
| No OpenAPI changes | Metadata fields empty | Supply non-empty Summary/Tags/etc. |
| Short-circuit missing | Status code not set | Provide ShortCircuitStatusCode |
| Can’t update existing route | Builder no longer accessible | Re-map route with new options |
Host header safety: If your app is reachable directly (not only behind a trusted reverse proxy), consider enabling Host Filtering to allow only expected hostnames. See the tutorial: Host Filtering.
Return to the Guides index.