In deel 1 hebben we de algemene architectuur van de ASP.NET Core aanvraag en reactie pijplijn onderzocht. Nu duiken we diep in de fundering laag: de server en hosting infrastructuur. Dit is waar alles begint waar uw toepassing tot leven komt en waar ruwe netwerkverzoeken worden omgezet in de gestructureerde HttpContext objecten die door uw middleware pijpleiding stromen.
Het begrijpen van deze laag is cruciaal omdat het bepaalt hoe uw applicatie start, hoe het is geconfigureerd, en hoe het interageert met de onderliggende webserver. Of u nu implementeert naar productie, het optimaliseren van de prestaties, of het configureren van HTTPS, de hostinglaag is waar deze problemen worden aangepakt.
OPMERKING: Dit is onderdeel van mijn experimenten met AI / een manier om $1000 Calude Code Web credits uit te geven. Ik heb dit een BUNCH van papieren, mijn begrip, vragen die ik moest genereren van dit artikel. Het is leuk en vult een gat dat ik niet ergens anders heb gezien gevuld.
ASP.NET Core scheidt de zorgen van applicatiehosting en webserveren in twee verschillende lagen:
Deze scheiding biedt flexibiliteit: u kunt servers (Kestrel, HTTP.sys, IIS Integration) ruilen zonder uw toepassingscode te wijzigen, of uw toepassing uitvoeren in verschillende hostingomgevingen (console app, Windows Service, systemd daemon) zonder de configuratie van de server te wijzigen.
In ASP.NET Core 6 en later is het hostingmodel vereenvoudigd met WebApplication en WebApplicationBuilder. Dit vervangt de oudere IHostBuilder en IWebHostBuilder patroon met een meer gestroomlijnde API.
// Modern ASP.NET Core 8 application
var builder = WebApplication.CreateBuilder(args);
// Configure services during the build phase
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Build the application
var app = builder.Build();
// Configure middleware after building
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
// Start the server and begin processing requests
app.Run();
Als je belt WebApplication.CreateBuilder(args), een aanzienlijke hoeveelheid initialisatie optreedt:
// Simplified view of what CreateBuilder does internally
public static WebApplicationBuilder CreateBuilder(string[] args)
{
var builder = new WebApplicationBuilder();
// 1. Configure the host defaults
// - Content root path (Directory.GetCurrentDirectory())
// - Load appsettings.json and appsettings.{Environment}.json
// - Load environment variables
// - Load command-line arguments
// - Setup default logging providers (Console, Debug, EventSource, EventLog on Windows)
// 2. Configure Kestrel as the default web server
builder.WebHost.UseKestrel();
// 3. Setup dependency injection container
// - Creates the IServiceCollection
// - Registers core services
// 4. Configure the environment
// - Sets ASPNETCORE_ENVIRONMENT (Development, Staging, Production)
// - Determines if running in development mode
// 5. Setup configuration system
// - Creates the IConfiguration hierarchy
// - Combines all configuration sources
return builder;
}
U heeft uitgebreide controle over hoe de host is geconfigureerd:
var builder = WebApplication.CreateBuilder(args);
// Configure Kestrel server options
builder.WebHost.ConfigureKestrel(serverOptions =>
{
serverOptions.Limits.MaxConcurrentConnections = 100;
serverOptions.Limits.MaxRequestBodySize = 10 * 1024 * 1024; // 10 MB
serverOptions.Limits.MinRequestBodyDataRate = new MinDataRate(
bytesPerSecond: 100,
gracePeriod: TimeSpan.FromSeconds(10)
);
});
// Add additional configuration sources
builder.Configuration.AddJsonFile("customsettings.json", optional: true);
builder.Configuration.AddEnvironmentVariables(prefix: "MYAPP_");
// Configure logging
builder.Logging.ClearProviders(); // Remove defaults
builder.Logging.AddConsole();
builder.Logging.AddDebug();
builder.Logging.SetMinimumLevel(LogLevel.Warning);
// Change the content root and web root
builder.Environment.ContentRootPath = "/custom/path";
builder.Environment.WebRootPath = "/custom/wwwroot";
var app = builder.Build();
De afhankelijkheid injectie container is gebouwd tijdens de host initialisatie. Diensten die hier geregistreerd zijn zijn beschikbaar tijdens uw toepassing:
var builder = WebApplication.CreateBuilder(args);
// Singleton: One instance for the application lifetime
builder.Services.AddSingleton<IMyService, MyService>();
// Scoped: One instance per request
builder.Services.AddScoped<IRequestService, RequestService>();
// Transient: New instance every time it's requested
builder.Services.AddTransient<ITransientService, TransientService>();
// Configure options pattern
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions")
);
// Access configuration directly during service registration
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<MyDbContext>(options =>
options.UseSqlServer(connectionString)
);
var app = builder.Build();
ASP.NET Core biedt een geavanceerd configuratiesysteem dat meerdere bronnen mergets:
var builder = WebApplication.CreateBuilder(args);
// Configuration is loaded in this order (later sources override earlier):
// 1. appsettings.json
// 2. appsettings.{Environment}.json
// 3. User secrets (in Development environment only)
// 4. Environment variables
// 5. Command-line arguments
// Access configuration
var mySetting = builder.Configuration["MySection:MySetting"];
var myValue = builder.Configuration.GetValue<int>("MySection:MyValue");
// Check environment
if (builder.Environment.IsDevelopment())
{
// Development-specific configuration
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
}
if (builder.Environment.IsProduction())
{
// Production-specific configuration
builder.Configuration.AddAzureKeyVault(/* ... */);
}
var app = builder.Build();
Kestrel is ASP.NET Core's cross-platform webserver. Het is snel, lichtgewicht en in staat om de productie werklast te verwerken. Het begrijpen van de mogelijkheden van Kestrel helpt u om de prestaties en veiligheid van uw applicatie te optimaliseren.
flowchart TD cc[Client Connection] ch["Connection Handler Layer<br/>• TLS/SSL Termination (if HTTPS)<br/>• Protocol Negotiation (HTTP/1.1, HTTP/2, HTTP/3)"] parser["HTTP Protocol Parser<br/>• Request Line Parsing (Method, Path, Protocol)<br/>• Header Parsing<br/>• Body Reading"] ctx["HttpContext Creation<br/>• Creates HttpContext object<br/>• Populates Request properties<br/>• Prepares Response object"] pipeline[Middleware Pipeline] cc --> ch --> parser --> ctx --> pipeline
Om te begrijpen hoe bytes een HttpContext worden die uw middleware kan gebruiken, helpt het om in te zoomen op Kestrel zijn interne stroom en verantwoordelijkheden.
flowchart LR
subgraph os[OS / Network Stack]
net[(TCP/UDP Sockets)]
end
subgraph kestrel[Kestrel Server]
accept["Connection Accept Loop<br/>(.NET Sockets)"]
subgraph connmw[Per-Connection Middleware]
tls["TLS Termination / ALPN<br/>(Selects HTTP/1.1 vs HTTP/2 vs HTTP/3)"]
limits["Connection & Request Limits<br/>(timeouts, sizes, rate limits)"]
logging[Connection Logging]
end
subgraph proto[Protocol Handlers]
h1["HTTP/1.1 Handler<br/>(keep-alive, chunked, pipelining)"]
h2["HTTP/2 Handler<br/>(multiplexing, HPACK)"]
h3["HTTP/3 Handler<br/>(QUIC, QPACK)"]
end
subgraph io[High-Perf IO]
pipes["System.IO.Pipelines<br/>(zero-copy buffers)"]
parser2[HTTP Parser]
end
features["Feature Mapping<br/>(IFeatureCollection)"]
ctxpool[HttpContext Pool]
appinvoke[IHttpApplication.ProcessRequestAsync]
end
app[Your Middleware Pipeline]
net --> accept --> connmw --> proto
proto --> io --> features --> ctxpool --> appinvoke --> app
sequenceDiagram
autonumber
participant C as Client
participant S as Socket
participant K as Kestrel
participant P as Protocol Handler
participant A as App (Middleware)
C->>S: Connect (TCP/QUIC)
S->>K: New connection accepted
K->>K: TLS handshake + ALPN
K->>P: Select protocol (HTTP/1.1, 2, or 3)
loop Read/Parse
P->>P: Read using System.IO.Pipelines
P->>P: Parse request line/headers/body
end
P->>K: Build features + rent HttpContext from pool
K->>A: ProcessRequestAsync(HttpContext)
A-->>K: Writes response via Pipes
K-->>C: Flush/Send response frames
Note over K,C: Backpressure applied when client is slow
Sleutel intern om te weten:
Je kunt configureren op welke eindpunten Kestrel luistert en hoe:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(options =>
{
// Listen on all network interfaces on port 5000 (HTTP)
options.Listen(IPAddress.Any, 5000);
// Listen on localhost port 5001 (HTTPS)
options.Listen(IPAddress.Loopback, 5001, listenOptions =>
{
listenOptions.UseHttps("certificate.pfx", "password");
});
// Listen on specific IP with HTTP/2
options.Listen(IPAddress.Parse("192.168.1.100"), 5002, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http2;
});
// Unix domain socket (Linux/macOS)
options.ListenUnixSocket("/tmp/myapp.sock");
// Named pipe (Windows)
options.ListenNamedPipe("mypipename");
});
var app = builder.Build();
Als alternatief kunt u eindpunten configureren via appsettings.json:
{
"Kestrel": {
"Endpoints": {
"Http": {
"Url": "http://localhost:5000"
},
"Https": {
"Url": "https://localhost:5001",
"Certificate": {
"Path": "certificate.pfx",
"Password": "your-password"
}
}
}
}
}
var builder = WebApplication.CreateBuilder(args);
// Endpoints are automatically configured from appsettings.json
// when you don't explicitly call ConfigureKestrel
var app = builder.Build();
HTTPS is essentieel voor productietoepassingen. Kestrel biedt verschillende manieren om TLS te configureren:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(options =>
{
options.Listen(IPAddress.Any, 5001, listenOptions =>
{
// Option 1: Certificate from file
listenOptions.UseHttps("certificate.pfx", "password");
// Option 2: Certificate from store (Windows)
listenOptions.UseHttps(storeCert =>
{
storeCert.Subject = "localhost";
storeCert.Store = "My";
storeCert.Location = StoreLocation.CurrentUser;
storeCert.AllowInvalid = false; // Don't allow invalid certs
});
// Option 3: Development certificate
listenOptions.UseHttps(); // Uses development certificate in Development environment
// Option 4: Configure TLS details
listenOptions.UseHttps(httpsOptions =>
{
httpsOptions.ServerCertificate = LoadCertificate();
httpsOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
httpsOptions.CheckCertificateRevocation = true;
httpsOptions.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13;
// Client certificate validation
httpsOptions.ClientCertificateValidation = (certificate, chain, errors) =>
{
// Custom validation logic
return errors == SslPolicyErrors.None;
};
});
});
});
var app = builder.Build();
Kestrel biedt tal van opties om het gebruik van hulpbronnen te controleren en de prestaties te optimaliseren:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(options =>
{
// Connection limits
options.Limits.MaxConcurrentConnections = 100;
options.Limits.MaxConcurrentUpgradedConnections = 100;
// Request limits
options.Limits.MaxRequestBodySize = 10 * 1024 * 1024; // 10 MB
options.Limits.MaxRequestHeaderCount = 100;
options.Limits.MaxRequestHeadersTotalSize = 32 * 1024; // 32 KB
options.Limits.MaxRequestLineSize = 8 * 1024; // 8 KB
// Keep-alive timeout
options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(2);
// Request header read timeout
options.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(30);
// Minimum data rate for request body
options.Limits.MinRequestBodyDataRate = new MinDataRate(
bytesPerSecond: 240,
gracePeriod: TimeSpan.FromSeconds(5)
);
// Minimum data rate for response body
options.Limits.MinResponseDataRate = new MinDataRate(
bytesPerSecond: 240,
gracePeriod: TimeSpan.FromSeconds(5)
);
// HTTP/2 specific limits
options.Limits.Http2.MaxStreamsPerConnection = 100;
options.Limits.Http2.HeaderTableSize = 4096;
options.Limits.Http2.MaxFrameSize = 16 * 1024; // 16 KB
options.Limits.Http2.MaxRequestHeaderFieldSize = 8 * 1024; // 8 KB
options.Limits.Http2.InitialConnectionWindowSize = 128 * 1024; // 128 KB
options.Limits.Http2.InitialStreamWindowSize = 96 * 1024; // 96 KB
});
var app = builder.Build();
Kestrel ondersteunt moderne HTTP protocollen:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(options =>
{
// HTTP/1.1 only
options.Listen(IPAddress.Any, 5000, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http1;
});
// HTTP/1.1 and HTTP/2
options.Listen(IPAddress.Any, 5001, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http1AndHttp2;
listenOptions.UseHttps();
});
// HTTP/2 only
options.Listen(IPAddress.Any, 5002, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http2;
listenOptions.UseHttps();
});
// HTTP/3 (QUIC) - requires .NET 7+
options.Listen(IPAddress.Any, 5003, listenOptions =>
{
listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
listenOptions.UseHttps();
});
});
var app = builder.Build();
Kestrel stelt de mogelijkheden van de server bloot via de IFeatureCollection beschikbaar op HttpContext:
app.Use(async (context, next) =>
{
// Check if HTTP/2 is being used
var http2Feature = context.Features.Get<IHttpRequestFeature>();
if (http2Feature?.Protocol == "HTTP/2")
{
Console.WriteLine("Using HTTP/2");
}
// Access connection features
var connectionFeature = context.Features.Get<IHttpConnectionFeature>();
Console.WriteLine($"Remote IP: {connectionFeature?.RemoteIpAddress}");
Console.WriteLine($"Local IP: {connectionFeature?.LocalIpAddress}");
// TLS information
var tlsFeature = context.Features.Get<ITlsConnectionFeature>();
if (tlsFeature?.ClientCertificate != null)
{
Console.WriteLine($"Client cert: {tlsFeature.ClientCertificate.Subject}");
}
// Request body pipe for high-performance scenarios
var bodyPipeFeature = context.Features.Get<IRequestBodyPipeFeature>();
if (bodyPipeFeature != null)
{
var reader = bodyPipeFeature.Reader;
// Use System.IO.Pipelines for zero-copy reads
}
await next(context);
});
De host biedt haken voor de toepassing levenscyclus gebeurtenissen:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Get the application lifetime
var lifetime = app.Services.GetRequiredService<IHostApplicationLifetime>();
// Application started event
lifetime.ApplicationStarted.Register(() =>
{
Console.WriteLine("Application has started");
// Perform startup tasks (warm up caches, etc.)
});
// Application stopping event
lifetime.ApplicationStopping.Register(() =>
{
Console.WriteLine("Application is stopping");
// Begin graceful shutdown (stop accepting new requests)
});
// Application stopped event
lifetime.ApplicationStopped.Register(() =>
{
Console.WriteLine("Application has stopped");
// Cleanup resources
});
app.Run();
U kunt ook implementeren IHostedService voor achtergrondtaken:
public class MyBackgroundService : IHostedService, IDisposable
{
private Timer? _timer;
private readonly ILogger<MyBackgroundService> _logger;
public MyBackgroundService(ILogger<MyBackgroundService> logger)
{
_logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Background service is starting");
_timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromMinutes(5));
return Task.CompletedTask;
}
private void DoWork(object? state)
{
_logger.LogInformation("Background service is working");
// Perform periodic work
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Background service is stopping");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
// Register the service
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHostedService<MyBackgroundService>();
var app = builder.Build();
ASP.NET Core verwerkt een sierlijke uitschakeling automatisch, maar u kunt het gedrag aanpassen:
var builder = WebApplication.CreateBuilder(args);
// Configure shutdown timeout
builder.WebHost.ConfigureKestrel(options =>
{
options.AddServerHeader = false; // Remove Server header for security
});
builder.Host.ConfigureHostOptions(options =>
{
// How long to wait for the application to shut down gracefully
options.ShutdownTimeout = TimeSpan.FromSeconds(30);
});
var app = builder.Build();
// During shutdown, Kestrel:
// 1. Stops accepting new connections
// 2. Waits for existing requests to complete (up to ShutdownTimeout)
// 3. Aborts remaining requests
// 4. Disposes services
// 5. Runs ApplicationStopped callbacks
app.Run();
In productie zit Kestrel meestal achter een omgekeerde proxy (nginx, Apache, IIS):
var builder = WebApplication.CreateBuilder(args);
// Configure forwarded headers for reverse proxy scenarios
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
// If your proxy is on a known network
options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("10.0.0.0"), 8));
options.KnownProxies.Add(IPAddress.Parse("10.0.0.1"));
// Required when running in containers/Kubernetes
options.ForwardedHeaders = ForwardedHeaders.All;
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
var app = builder.Build();
// Must be before other middleware
app.UseForwardedHeaders();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
var builder = WebApplication.CreateBuilder(args);
// Enable Windows Service lifetime
builder.Host.UseWindowsService();
// Configure content root for Windows Service
builder.Host.UseContentRoot(AppContext.BaseDirectory);
var app = builder.Build();
app.Run();
var builder = WebApplication.CreateBuilder(args);
// Enable systemd lifetime
builder.Host.UseSystemd();
var app = builder.Build();
app.Run();
Terwijl Kestrel de standaardkeuze is, kunt u indien nodig een aangepaste server implementeren:
public class CustomServer : IServer
{
private IFeatureCollection _features = new FeatureCollection();
public IFeatureCollection Features => _features;
public Task StartAsync<TContext>(IHttpApplication<TContext> application,
CancellationToken cancellationToken) where TContext : notnull
{
// Start listening for connections
// Create HttpContext for each request
// Invoke application.ProcessRequestAsync(httpContext)
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
// Stop accepting new connections
// Wait for existing requests to complete
return Task.CompletedTask;
}
public void Dispose()
{
// Cleanup resources
}
}
// Use custom server
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseServer(new CustomServer());
var app = builder.Build();
HttpContext objecten die door de middleware pijpleiding stromenIFeatureCollection biedt toegang tot servermogelijkheden op laag niveauHet begrijpen van de server- en hostinglaag geeft je de controle over hoe je applicatie start, hoe het met verbindingen omgaat en hoe het werkt onder belasting. Deze basis ondersteunt alles wat er gebeurt in de lagen hierboven.
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.