0Pricing
C# Academy · Leçon

Écrire des intergiciels personnalisés

Créez des intergiciels intégrés avec Use/Run/Map et des intergiciels fondés sur des classes avec InvokeAsync pour obtenir des composants réutilisables.

Écrire des intergiciels personnalisés est une leçon C# Academy gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage C# Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours C# Academy comprend 4 leçons au total.

Pourquoi créer un intergiciel personnalisé ?

Un intergiciel personnalisé prend en charge des préoccupations transversales qui s’appliquent à de nombreuses requêtes : journalisation, mesure du temps, gestion des erreurs, authentification, compression et mise en cache. Écrire cette logique une seule fois permet de l’exécuter automatiquement pour chaque requête correspondante.

Intergiciel en ligne avec Use

La manière la plus rapide d’ajouter un intergiciel consiste à transmettre un délégué à app.Use(). Cette approche convient au prototypage ou à une logique réellement simple.

app.Use(async (context, next) =>
{
    var start = DateTimeOffset.UtcNow;

    await next(context);

    var elapsed = DateTimeOffset.UtcNow - start;
    context.Response.Headers.Append(
        "X-Elapsed", elapsed.TotalMilliseconds.ToString("F0") + "ms");
});

Intergiciel basé sur une classe (convention)

Une classe d’intergiciel conventionnelle possède un constructeur qui reçoit RequestDelegate et une méthode publique InvokeAsync. Des paramètres supplémentaires du constructeur peuvent être injectés depuis DI.

public class SecurityHeadersMiddleware
{
    private readonly RequestDelegate _next;

    public SecurityHeadersMiddleware(RequestDelegate next) => _next = next;

    public async Task InvokeAsync(HttpContext context)
    {
        var headers = context.Response.Headers;
        headers.Append("X-Content-Type-Options", "nosniff");
        headers.Append("X-Frame-Options", "DENY");
        headers.Append("X-XSS-Protection", "1; mode=block");
        headers.Append("Referrer-Policy", "strict-origin-when-cross-origin");

        await _next(context);
    }
}

// Extension method for clean registration:
public static class SecurityHeadersExtensions
{
    public static IApplicationBuilder UseSecurityHeaders(
        this IApplicationBuilder app) =>
        app.UseMiddleware<SecurityHeadersMiddleware>();
}

IMiddleware pour les dépendances à portée limitée

Si votre intergiciel nécessite des services à durée de vie limitée, comme DbContext, implémentez IMiddleware. Enregistrez-le avec une portée limitée ; l’infrastructure le résout à nouveau pour chaque requête.

public class AuditMiddleware : IMiddleware
{
    private readonly AuditDbContext _db;
    private readonly IHttpContextAccessor _http;

    public AuditMiddleware(AuditDbContext db, IHttpContextAccessor http)
    {
        _db = db;
        _http = http;
    }

    public async Task InvokeAsync(HttpContext ctx, RequestDelegate next)
    {
        await next(ctx);

        if (ctx.Request.Method != "GET")
        {
            _db.AuditLogs.Add(new AuditLog
            {
                User   = ctx.User.Identity?.Name,
                Path   = ctx.Request.Path,
                Status = ctx.Response.StatusCode,
                At     = DateTime.UtcNow
            });
            await _db.SaveChangesAsync();
        }
    }
}

builder.Services.AddScoped<AuditMiddleware>();
app.UseMiddleware<AuditMiddleware>();

Intergiciel avec options

Transmettez la configuration à l’intergiciel via un objet d’options dans le constructeur. Enregistrez les options auprès du conteneur DI ou transmettez-les directement lors de l’enregistrement de l’intergiciel.

public class ThrottleOptions
{
    public int MaxRequestsPerSecond { get; set; } = 100;
    public string[] ExcludedPaths { get; set; } = Array.Empty<string>();
}

public class ThrottleMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ThrottleOptions _options;

    public ThrottleMiddleware(RequestDelegate next, ThrottleOptions options)
    {
        _next   = next;
        _options = options;
    }
    // ...
}

// Registration with options:
app.UseMiddleware<ThrottleMiddleware>(new ThrottleOptions
{
    MaxRequestsPerSecond = 50
});

Intergiciel de gestion des exceptions

Un intergiciel personnalisé de gestion des exceptions intercepte toutes les exceptions non gérées et renvoie des réponses d’erreur structurées.

public class GlobalExceptionMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<GlobalExceptionMiddleware> _logger;

    public GlobalExceptionMiddleware(RequestDelegate next, ILogger<GlobalExceptionMiddleware> l)
    {
        _next = next;
        _logger = l;
    }

    public async Task InvokeAsync(HttpContext ctx)
    {
        try { await _next(ctx); }
        catch (NotFoundException ex)
        {
            ctx.Response.StatusCode = 404;
            await ctx.Response.WriteAsJsonAsync(new { error = ex.Message });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Unhandled exception");
            ctx.Response.StatusCode = 500;
            await ctx.Response.WriteAsJsonAsync(new { error = "Internal server error" });
        }
    }
}

Intergiciel de journalisation des requêtes

Un intergiciel structuré de journalisation des requêtes et des réponses enregistre la méthode, le chemin, le code d’état et le temps écoulé pour chaque requête.

public class RequestLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<RequestLoggingMiddleware> _log;

    public RequestLoggingMiddleware(RequestDelegate n, ILogger<RequestLoggingMiddleware> l)
    { _next = n; _log = l; }

    public async Task InvokeAsync(HttpContext ctx)
    {
        var sw = System.Diagnostics.Stopwatch.StartNew();
        await _next(ctx);
        sw.Stop();

        _log.LogInformation(
            "{Method} {Path} -> {Status} in {Ms}ms",
            ctx.Request.Method,
            ctx.Request.Path,
            ctx.Response.StatusCode,
            sw.ElapsedMilliseconds);
    }
}

Intergiciel conditionnel avec UseWhen

UseWhen crée une branche conditionnelle dans la chaîne de traitement en fonction d’un prédicat, sans la diviser définitivement. La branche rejoint la chaîne de traitement principale après son exécution.

// Apply authentication middleware only to /api/* routes
app.UseWhen(
    ctx => ctx.Request.Path.StartsWithSegments("/api"),
    apiApp =>
    {
        apiApp.UseAuthentication();
        apiApp.UseAuthorization();
    });

// Public routes (/public/*) bypass authentication
app.MapGet("/public/health", () => "OK");
app.MapGet("/api/data", [Authorize] async (DataService s) => await s.GetAsync());

Intergiciel de mise en cache des réponses

L’intergiciel intégré de mise en cache des réponses conserve les réponses complètes en mémoire. Configurez les politiques de cache pour chaque point de terminaison à l’aide d’en-têtes ou d’attributs.

builder.Services.AddResponseCaching();

app.UseResponseCaching();

app.MapGet("/products", async (AppDbContext db) =>
{
    var products = await db.Products.AsNoTracking().ToListAsync();
    return Results.Ok(products);
})
.CacheOutput(p => p.Expire(TimeSpan.FromMinutes(2)).Tag("products"));

En pratique : intergiciel du mode maintenance

Un intergiciel de mode maintenance lit un indicateur dans la configuration, avec prise en charge du rechargement à chaud via IOptionsMonitor, et rejette les requêtes autres que celles de vérification de l’état de santé pendant la maintenance.

public class MaintenanceMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IOptionsMonitor<MaintenanceOptions> _options;

    public MaintenanceMiddleware(RequestDelegate next,
        IOptionsMonitor<MaintenanceOptions> opts)
    { _next = next; _options = opts; }

    public async Task InvokeAsync(HttpContext ctx)
    {
        if (_options.CurrentValue.IsEnabled
            && !ctx.Request.Path.StartsWithSegments("/health"))
        {
            ctx.Response.StatusCode = 503;
            ctx.Response.Headers.Append("Retry-After", "300");
            await ctx.Response.WriteAsJsonAsync(
                new { message = "Service under maintenance" });
            return;
        }
        await _next(ctx);
    }
}

Vérification rapide

Pourquoi devriez-vous implémenter IMiddleware plutôt que l’approche conventionnelle lorsque vous avez besoin d’un service à portée limitée, comme DbContext ?

Récapitulatif : écrire des intergiciels personnalisés

Points clés à retenir :

  • En ligne, avec un délégué Use : rapide, idéal pour une ou deux lignes ; basé sur une classe : réutilisable et testable
  • Classe conventionnelle : le constructeur reçoit RequestDelegate ; InvokeAsync(HttpContext)
  • IMiddleware : résolution DI par requête, requise pour les dépendances à portée limitée
  • UseWhen : branchement conditionnel qui rejoint à nouveau la chaîne de traitement principale
  • Écrivez d’abord l’intergiciel de gestion des exceptions, à l’extérieur de tous les autres, afin d’intercepter toutes les erreurs
  • Créez des méthodes d’extension (UseXxx) pour un enregistrement clair et facile à découvrir

Questions Fréquemment Posées

La leçon « Écrire des intergiciels personnalisés » est-elle gratuite ?

Oui — le texte complet de « Écrire des intergiciels personnalisés » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours C# Academy, passe à CoddyKit PRO. Le cours C# Academy comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Écrire des intergiciels personnalisés » ?

Créez des intergiciels intégrés avec Use/Run/Map et des intergiciels fondés sur des classes avec InvokeAsync pour obtenir des composants réutilisables. Tu pratiques C# Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer C# Academy ?

Aucune expérience préalable n'est requise. C# Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.

Combien de temps prend la leçon « Écrire des intergiciels personnalisés » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon C# Academy ?

Oui. Chaque leçon C# Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Vue d’ensemble de la chaîne ASP.NET Core
  2. Écrire des intergiciels personnalisés
  3. Court-circuitage et branchement
  4. Ordre des intergiciels et intergiciels intégrés
← Retour à C# Academy