Comprendre l’ASP.NET Core Request and Response Pipeline - Part 2: Server and Hosting Layer (Français (French))

Comprendre l’ASP.NET Core Request and Response Pipeline - Part 2: Server and Hosting Layer

Sunday, 09 November 2025

//

15 minute read

Introduction

Dans la partie 1,, nous avons étudié l’architecture globale de l’ASP .NET Core Requête et pipeline d’intervention. MaintenantMSC3 nousM SK4 allons plonger dans le fondement de la couche de baseMST5 le serveur et l’infrastructure d’hébergementMSL6 C’est là où tout commenceMSR7où votre application prend vie et où les demandes de réseau brutes sont transformées en structure HttpContext objects qui traversent votre pipeline de middleware.

La compréhension de cette couche est cruciale parce qu’elle contrôle la façon dont votre application se démarre, comment elle est configurée' , et comment elle interagit avec le serveur Web sous-jacent.

NOTE: Il s'agit d'une partie de mes expériences avec l'AI / une façon d'épargner $1000 Code Calude Crédits WebM SK3 J'ai alimenté cet article par un BUNCH de documentsMSC5 ma compréhensionMST6 des questions que j'ai eues pour générer cet articleMst7 C'est fun et remplit une lacune que je n'ai jamais vu remplie ailleursM st10

L’architecture de deux niveaux-Layer: Host et serveur

ASP.NET Core sépare les préoccupations liées à l’hébergement d’application et au service Web en deux couches distinctes

  1. L'hôte - Gestion de la durée de vie de l'application, configurationM SK2 injection de dépendance , et enregistrement
  2. Le serveur - Génie les communications HTTP, écoute les demandes , et gère les connexions

Cette séparation offre de la souplesse: vous pouvez échanger des serveurs (Kestrel, HTTPMSC3sysM SK4 IIS IntegrationMska5 sans modifier votre code d'applicationMka6 ou exploiter votre application dans différents environnements d'hébergement MKA7console appMsaka8 Windows ServiceM KA9 daemon systématiqueMSKA10 sans modification de la configuration du serveurMkka11

La couche d'hôte

Application Web et WebApplicationBuilder

Dans ASP.NET Core M SK1 et plus tard,, le modèle d’hébergement a été simplifié avec WebApplication et WebApplicationBuilder. Cet élément a remplacé l'ancien IHostBuilder et IWebHostBuilder modèle avec un API plus simplifié.

// 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();

Ce qui se passe pendant l'application Web.CreateBuilder()?

Lorsque vous appelez WebApplication.CreateBuilder(args), une quantité substantielle d’initialisation se produit

// 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;
}

Customisation de l'hôte

Vous avez un grand contrôle sur la configuration de l'hôte:

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();

Le conteneur de service

Le contenant d'injection dépendance est construit pendant l'initialisation de l'hôte. Les services enregistrés ici sont disponibles dans toute votre application:

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();

Environnement et configuration

ASP.NET Core fournit un système de configuration sophistiqué qui fusionne plusieurs sources.

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();

La couche du serveur: Kestrel

Kestrel est ASP.NET CoreM SK1s cross-platform web serverMST3 IlMSC4s fastMSL5 lightweightMSR6 and capable of handling production workloadsMSV7 Comprendre les fonctionnalités de kestrelMLS8 vous aide à optimiser votre applicationMSSL9s performance and securityMSS10

Architecture Kestrel

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

Architecture Kestrel - plongée plus profonde

Pour comprendre comment les octets deviennent un HttpContexte que votre outil de middleware peut utiliser, il aide à zoomer sur Kestrel ’ le flux et les responsabilités internes

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

Key internals to know:

  • La sélection TLS et ALPN détermine quel gestionnaire de protocoles fonctionne pour cette connexion.
  • Système.IOM SK1Les pipelines soutiennent tout le traitement et l’écriture pour des allocations minimales et un haut débit.
  • Mapping des caractéristiques (IFeatureCollection) expose les capacités de serveur à faible niveauM SK2à HttpContext sans le lier aux types KestrelMSC3
  • Les objets de HttpContext sont mis en commun pour réduire la pression GC; ilsM SK1re reset et réutilisés par demande.
  • La pression arrière est appliquée à travers les tuyaux lorsque le client peut’t lire assez rapidementM SK1le serveur remporte’t surMSC3l'interrupteur écrit .
  • Démarrages et limites de temps (keepM SK1alive, headers , taille du corps de la demandeMST4 HTTPMSC5 limites des fluxMSL6 protéger le serveur contre le ralentissement et l'épuisement des ressourcesMSSK7
  • Threading: la plupart des travaux sont exécutés sur le ThreadPool; les gestionnaires de protocole évitent la création d'un thread par demande de messagerie et favorisent les poursuites asynciquesM SK3

Configuration des points finals de Kestrel

Vous pouvez configurer les points de fin sur lesquels Kestrel écoute et comment:

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();

Par ailleurs, vous pouvez configurer les points finals par l'entremise des paramètres d'app

{
  "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();

Configuration HTTPS

HTTPS est essentiel pour les applications de production. Kestrel offre plusieurs façons de configurer TLS:

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();

Limites de Kestrel et ajustement du rendement

Kestrel offre de nombreuses options pour contrôler l'utilisation des ressources et optimiser la performance:

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();

Soutien HTTP/2 et HTTP /3

Kestrel appuie les protocoles HTTP modernes:

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();

Caractéristiques du serveur

Kestrel expose les capacités du serveur par le biais de IFeatureCollection à l'adresse suivante : 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);
});

Événements pendant la vie de l'application

L'hôte fournit des crochets pour les événements du cycle de vie de l'application:

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();

Vous pouvez également mettre en œuvre IHostedService pour les tâches de fond:

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();

Fermeture gracieuse

ASP.NET Core gère l'arrêt gracieux automatiquement, mais vous pouvez personnaliser le comportement

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();

Scénarios d'hébergement de production

Utilisation d'un proxy inverse

Dans la production, Kestrel est habituellement derrière un proxy inverse M SK1nginx, Apache , IISMSC4

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();

Windows Service Hosting

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();

Système d'hébergement de services Linux

var builder = WebApplication.CreateBuilder(args);

// Enable systemd lifetime
builder.Host.UseSystemd();

var app = builder.Build();

app.Run();

Amélioré: Server personnalisé

Si Kestrel est le choix standard, vous pouvez mettre en place un serveur personnalisé si nécessaire:

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();

Key Takeaways

  • L'hôte gère la durée de vie de l'application, configuration , DI, et l'enregistrement
  • Kestrel est un serveur Web de haut niveau sur une plate-forme
  • Vous pouvez configurer les points de fin, HTTPS , protocoles, et les limites de performance
  • Le serveur crée HttpContext les objets qui traversent le pipeline de middleware
  • Un arrêt gracieux garantit que les demandes sont remplies avant la fin de l'application
  • Les déploiements de production utilisent généralement Kestrel derrière un proxy inverse
  • L'article 5 de la Loi sur l'immigration et le statut des réfugiés IFeatureCollection fournit un accès aux capacités de serveur à faible niveau -

La compréhension du serveur et de la couche d’hébergement vous donne le contrôle sur la façon dont votre application se démarre, comment elle gère les connexionsM SK1 et comment elle fonctionne sous charge. Cette fondation appuie tout ce qui se passe dans les couches ci-dessus .


Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.