Démarrage d’une application dans ASP.NET Core

Remarque

Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version ASP.NET Core 8.0 de cet article.

Par Rick Anderson

Les applications ASP.NET Core créées avec les modèles web contiennent le code de démarrage de l’application dans le fichier Program.cs.

Le code de démarrage d’application suivant prend en charge les éléments suivants :

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapGet("/hi", () => "Hello!");

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Les applications utilisant EventSource peuvent mesurer le temps de démarrage pour comprendre et optimiser les performances de démarrage. L’événement ServerReady dans Microsoft.AspNetCore.Hosting représente le point où le serveur est prêt à répondre aux demandes.

Pour plus d’informations sur le démarrage de l’application, consultez ASP.NET Core vue d’ensemble des principes fondamentaux.

Étendre le démarrage avec les filtres de démarrage

Utilisez IStartupFilter :

  • Pour configurer l’intergiciel (middleware) au début ou à la fin du pipeline d’intergiciels d’une application sans appel explicite à Use{Middleware}. Permet IStartupFilter d’ajouter des valeurs par défaut au début du pipeline sans inscrire explicitement l’intergiciel par défaut. IStartupFilter permet à un autre composant d’appeler Use{Middleware} au nom de l’auteur de l’application.
  • Pour créer un pipeline de méthodes Configure. IStartupFilter.Configure peut définir un middleware à exécuter avant ou après les middlewares qui sont ajoutés par les bibliothèques.

IStartupFilter implémente Configure, qui reçoit et retourne un Action<IApplicationBuilder>. IApplicationBuilder définit une classe pour configurer le pipeline de requête d’une application. Pour plus d’informations, consultez Créer un pipeline de middlewares avec IApplicationBuilder.

Chaque IStartupFilter peut ajouter un ou plusieurs middlewares au pipeline de requête. Les filtres sont appelés dans l’ordre dans lequel ils ont été ajoutés au conteneur de service. Les filtres peuvent ajouter l’intergiciel avant ou après la transmission du contrôle au filtre suivant. Par conséquent, ils s’ajoutent au début ou à la fin du pipeline de l’application.

L’exemple suivant montre comment inscrire un middleware auprès de IStartupFilter. Le middleware RequestSetOptionsMiddleware définit une valeur d’options à partir d’un paramètre de chaîne de requête :

public class RequestSetOptionsMiddleware
{
    private readonly RequestDelegate _next;

    public RequestSetOptionsMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    // Test with https://localhost:5001/Privacy/?option=Hello
    public async Task Invoke(HttpContext httpContext)
    {
        var option = httpContext.Request.Query["option"];

        if (!string.IsNullOrWhiteSpace(option))
        {
            httpContext.Items["option"] = WebUtility.HtmlEncode(option);
        }

        await _next(httpContext);
    }
}

RequestSetOptionsMiddleware est configuré dans la classe RequestSetOptionsStartupFilter :

namespace WebStartup.Middleware;
// <snippet1>
public class RequestSetOptionsStartupFilter : IStartupFilter
{
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        return builder =>
        {
            builder.UseMiddleware<RequestSetOptionsMiddleware>();
            next(builder);
        };
    }
}
// </snippet1>

Le IStartupFilter est inscrit dans Program.cs :

using WebStartup.Middleware;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddTransient<IStartupFilter,
                      RequestSetOptionsStartupFilter>();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Quand un paramètre de chaîne de requête pour option est fourni, le middleware traite l’affectation de valeur avant que le middleware ASP.NET Core n’affiche la réponse :

@page
@model PrivacyModel
@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<p> Append query string ?option=hello</p>
Option String: @HttpContext.Items["option"];

L’ordre d’exécution de l’intergiciel est défini par l’ordre des inscriptions d’IStartupFilter :

  • Plusieurs implémentations d’IStartupFilter peuvent interagir avec les mêmes objets. Si l’ordre est important, définissez l’ordre des inscriptions de leurs services IStartupFilter pour qu’il corresponde à l’ordre dans lequel leurs intergiciels doivent s’exécuter.

  • Les bibliothèques peuvent ajouter des intergiciels avec une ou plusieurs implémentations IStartupFilter qui s’exécutent avant ou après l’autre intergiciel d’application inscrit avec IStartupFilter. Pour appeler un middleware IStartupFilter avant un middleware ajouté par le IStartupFilter d’une bibliothèque :

    • Placez l’inscription du service avant l’ajout de la bibliothèque au conteneur de service.
    • Pour les appels suivants, placez l’inscription du service après l’ajout de la bibliothèque.

Remarque : Vous ne pouvez pas étendre l’application ASP.NET Core lorsque vous remplacez Configure. Pour plus d’informations sur la mise en forme, consultez ce problème GitHub.

Ajouter la configuration au démarrage à partir d’un assembly externe

Une implémentation de IHostingStartup permet d’ajouter des améliorations à une application au démarrage à partir d’un assembly externe, en dehors de le fichier Program.cs de l’application. Pour plus d’informations, consultez Utiliser des assemblys d’hébergement au démarrage dans ASP.NET Core.

Startup, ConfigureServices et Configure

Pour plus d’informations sur l’utilisation des méthodes ConfigureServices et Configure avec le modèle d’hébergement minimal, consultez :

Les applications ASP.NET Core créées avec les modèles web contiennent le code de démarrage de l’application dans le fichier Program.cs.

Le code de démarrage d’application suivant prend en charge les éléments suivants :

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapGet("/hi", () => "Hello!");

app.MapDefaultControllerRoute();
app.MapRazorPages();

app.Run();

Pour plus d’informations sur le démarrage de l’application, consultez ASP.NET Core vue d’ensemble des principes fondamentaux.

Étendre le démarrage avec les filtres de démarrage

Utilisez IStartupFilter :

  • Pour configurer l’intergiciel (middleware) au début ou à la fin du pipeline d’intergiciels d’une application sans appel explicite à Use{Middleware}. Permet IStartupFilter d’ajouter des valeurs par défaut au début du pipeline sans inscrire explicitement l’intergiciel par défaut. IStartupFilter permet à un autre composant d’appeler Use{Middleware} au nom de l’auteur de l’application.
  • Pour créer un pipeline de méthodes Configure. IStartupFilter.Configure peut définir un middleware à exécuter avant ou après les middlewares qui sont ajoutés par les bibliothèques.

IStartupFilter implémente Configure, qui reçoit et retourne un Action<IApplicationBuilder>. IApplicationBuilder définit une classe pour configurer le pipeline de requête d’une application. Pour plus d’informations, consultez Créer un pipeline de middlewares avec IApplicationBuilder.

Chaque IStartupFilter peut ajouter un ou plusieurs middlewares au pipeline de requête. Les filtres sont appelés dans l’ordre dans lequel ils ont été ajoutés au conteneur de service. Les filtres peuvent ajouter l’intergiciel avant ou après la transmission du contrôle au filtre suivant. Par conséquent, ils s’ajoutent au début ou à la fin du pipeline de l’application.

L’exemple suivant montre comment inscrire un middleware auprès de IStartupFilter. Le middleware RequestSetOptionsMiddleware définit une valeur d’options à partir d’un paramètre de chaîne de requête :

public class RequestSetOptionsMiddleware
{
    private readonly RequestDelegate _next;

    public RequestSetOptionsMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    // Test with https://localhost:5001/Privacy/?option=Hello
    public async Task Invoke(HttpContext httpContext)
    {
        var option = httpContext.Request.Query["option"];

        if (!string.IsNullOrWhiteSpace(option))
        {
            httpContext.Items["option"] = WebUtility.HtmlEncode(option);
        }

        await _next(httpContext);
    }
}

RequestSetOptionsMiddleware est configuré dans la classe RequestSetOptionsStartupFilter :

namespace WebStartup.Middleware;
// <snippet1>
public class RequestSetOptionsStartupFilter : IStartupFilter
{
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        return builder =>
        {
            builder.UseMiddleware<RequestSetOptionsMiddleware>();
            next(builder);
        };
    }
}
// </snippet1>

Le IStartupFilter est inscrit dans Program.cs :

using WebStartup.Middleware;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddTransient<IStartupFilter,
                      RequestSetOptionsStartupFilter>();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Quand un paramètre de chaîne de requête pour option est fourni, le middleware traite l’affectation de valeur avant que le middleware ASP.NET Core n’affiche la réponse :

@page
@model PrivacyModel
@{
    ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>

<p> Append query string ?option=hello</p>
Option String: @HttpContext.Items["option"];

L’ordre d’exécution de l’intergiciel est défini par l’ordre des inscriptions d’IStartupFilter :

  • Plusieurs implémentations d’IStartupFilter peuvent interagir avec les mêmes objets. Si l’ordre est important, définissez l’ordre des inscriptions de leurs services IStartupFilter pour qu’il corresponde à l’ordre dans lequel leurs intergiciels doivent s’exécuter.

  • Les bibliothèques peuvent ajouter des intergiciels avec une ou plusieurs implémentations IStartupFilter qui s’exécutent avant ou après l’autre intergiciel d’application inscrit avec IStartupFilter. Pour appeler un middleware IStartupFilter avant un middleware ajouté par le IStartupFilter d’une bibliothèque :

    • Placez l’inscription du service avant l’ajout de la bibliothèque au conteneur de service.
    • Pour les appels suivants, placez l’inscription du service après l’ajout de la bibliothèque.

Remarque : Vous ne pouvez pas étendre l’application ASP.NET Core lorsque vous remplacez Configure. Pour plus d’informations, consultez ce problème GitHub.

Ajouter la configuration au démarrage à partir d’un assembly externe

Une implémentation de IHostingStartup permet d’ajouter des améliorations à une application au démarrage à partir d’un assembly externe, en dehors de le fichier Program.cs de l’application. Pour plus d’informations, consultez Utiliser des assemblys d’hébergement au démarrage dans ASP.NET Core.

La classe Startup configure les services et le pipeline de demande de l’application.

Classe Startup

Les applications ASP.NET Core utilisent une classe de Startup, qui est nommée Startup par convention. La classe Startup :

  • Inclut éventuellement une méthode ConfigureServices pour configurer les services de l’application. Un service est un composant réutilisable qui fournit une fonctionnalité d’application. Les services sont inscrits dans ConfigureServices et consommés dans l’application par injection de dépendance ou ApplicationServices.
  • Inclut une méthode Configure pour créer le pipeline de traitement des requêtes de l’application.

ConfigureServices et Configure sont appelés par le runtime ASP.NET Core au lancement de l’application :

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
        });
    }
}

L’échantillon précédent concerne les Pages Razor, toutefois, la version MVC est similaire.

La classe Startup est spécifiée quand l’hôte de l’application est créé. La classe Startup est généralement spécifiée en appelant la méthode WebHostBuilderExtensions.UseStartup/<TStartup> dans le générateur d’hôte :

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

L’hôte fournit des services accessibles au constructeur de classe Startup. L’application ajoute des services supplémentaires à l’aide de ConfigureServices. Les services de l’hôte ainsi que ceux de l’application sont disponibles dans Configure et dans l’ensemble de l’application.

Seuls les types de service suivants peuvent être injectés dans le constructeur Startup lorsque vous utilisez l’hôte générique (IHostBuilder) :

public class Startup
{
    private readonly IWebHostEnvironment _env;

    public Startup(IConfiguration configuration, IWebHostEnvironment env)
    {
        Configuration = configuration;
        _env = env;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        if (_env.IsDevelopment())
        {
        }
        else
        {
        }
    }
}

La plupart des services ne sont pas disponibles tant que la méthode Configure n’est pas appelée.

Démarrage multiple

Quand l’application définit différentes classes Startup pour différents environnements (par exemple, StartupDevelopment), la classe Startup appropriée est sélectionnée au moment de l’exécution. La classe dont le suffixe du nom correspond à l'environnement actuel est prioritaire. Si l’application est exécutée dans l’environnement de développement et comprend à la fois une classe Startup et une classe StartupDevelopment, la classe StartupDevelopment est utilisée. Pour plus d’informations, consultez Utiliser plusieurs environnements.

Pour plus d’informations sur l’hôte, consultez L’hôte. Pour plus d’informations sur la gestion des erreurs lors du démarrage, consultez Gestion des exceptions de démarrage.

Méthode ConfigureServices

La méthode ConfigureServices est :

  • facultatif.
  • Appelée par l’hôte avant la méthode Configure pour configurer les services de l’application
  • L’emplacement où les options de configuration sont définies par convention.

L’hôte peut configurer certains services avant l’appel des méthodes Startup. Pour plus d’informations, consultez L’hôte.

Pour les fonctionnalités qui nécessitent une configuration importante, il existe des méthodes d’extension Add{Service} pour IServiceCollection. Par exemple, AjouterDbContext, AjouterPar défautIdentity, AjouterEntityFrameworkStores et AjouterRazorPages :

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {

        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>(
            options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddRazorPages();
    }

L’ajout de services au conteneur de service les rend disponibles dans l’application et dans la méthode Configure. Les services sont résolus via l’injection de dépendances ou à partir de ApplicationServices.

Méthode Configure

La méthode Configure permet de spécifier le mode de réponse de l’application aux requêtes HTTP. Vous configurez le pipeline de requête en ajoutant des composants d’intergiciel (middleware) à une instance de IApplicationBuilder. IApplicationBuilder est disponible pour la méthode Configure, mais elle n’est pas inscrite dans le conteneur de service. L’hébergement crée un IApplicationBuilder et le passe directement à Configure.

Les modèles ASP.NET Core configurent le pipeline pour permettre la prise en charge des éléments suivants :

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
        });
    }
}

L’échantillon précédent concerne les Pages Razor, toutefois, la version MVC est similaire.

Chaque méthode d’extension Use ajoute un ou plusieurs composants de middleware au pipeline de requête. Par exemple, UseStaticFiles configure le middleware pour qu’il traite des fichiers statiques.

Chaque composant de middleware du pipeline des requêtes est chargé d’appeler le composant suivant du pipeline ou de court-circuiter la chaîne, si c’est approprié.

Vous pouvez spécifier des services supplémentaires (comme IWebHostEnvironment, ILoggerFactory et tout service défini dans ConfigureServices) dans la signature de la méthode Configure. Ces services sont injectés s’ils sont disponibles.

Pour plus d’informations sur l’utilisation de IApplicationBuilder et l’ordre de traitement des middlewares, consultez ASP.NET Core Middleware.

Configurer des services sans démarrage

Pour configurer les services et le pipeline de traitement de requête sans utiliser de classe Startup, appelez les méthodes pratiques ConfigureServices et Configure sur le générateur de l’hôte. Les appels multiples à ConfigureServices s’ajoutent les uns aux autres. S’il existe plusieurs appels de méthode Configure, le dernier appel de Configure est utilisé.

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((hostingContext, config) =>
            {
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.ConfigureServices(services =>
                {
                    services.AddControllersWithViews();
                })
                .Configure(app =>
                {
                    var loggerFactory = app.ApplicationServices
                        .GetRequiredService<ILoggerFactory>();
                    var logger = loggerFactory.CreateLogger<Program>();
                    var env = app.ApplicationServices.GetRequiredService<IWebHostEnvironment>();
                    var config = app.ApplicationServices.GetRequiredService<IConfiguration>();

                    logger.LogInformation("Logged in Configure");

                    if (env.IsDevelopment())
                    {
                        app.UseDeveloperExceptionPage();
                    }
                    else
                    {
                        app.UseExceptionHandler("/Home/Error");
                        app.UseHsts();
                    }

                    var configValue = config["MyConfigKey"];
                });
            });
        });
}

Étendre le démarrage avec les filtres de démarrage

Utilisez IStartupFilter :

  • Pour configurer l’intergiciel au début ou à la fin d’une application, configurez le pipeline d’intergiciel sans appel explicite à Use{Middleware}. IStartupFilter est utilisé par ASP.NET Core pour ajouter des valeurs par défaut au début du pipeline sans avoir à inscrire explicitement l’intergiciel par défaut à l’auteur de l’application. IStartupFilter permet à un autre composant d’appeler Use{Middleware} au nom de l’auteur de l’application.
  • Pour créer un pipeline de méthodes Configure. IStartupFilter.Configure peut définir un middleware à exécuter avant ou après les middlewares qui sont ajoutés par les bibliothèques.

IStartupFilter implémente Configure, qui reçoit et retourne un Action<IApplicationBuilder>. IApplicationBuilder définit une classe pour configurer le pipeline de requête d’une application. Pour plus d’informations, consultez Créer un pipeline de middlewares avec IApplicationBuilder.

Chaque IStartupFilter peut ajouter un ou plusieurs middlewares au pipeline de requête. Les filtres sont appelés dans l’ordre dans lequel ils ont été ajoutés au conteneur de service. Les filtres peuvent ajouter l’intergiciel avant ou après la transmission du contrôle au filtre suivant. Par conséquent, ils s’ajoutent au début ou à la fin du pipeline de l’application.

L’exemple suivant montre comment inscrire un middleware auprès de IStartupFilter. Le middleware RequestSetOptionsMiddleware définit une valeur d’options à partir d’un paramètre de chaîne de requête :

public class RequestSetOptionsMiddleware
{
    private readonly RequestDelegate _next;

    public RequestSetOptionsMiddleware( RequestDelegate next )
    {
        _next = next;
    }

    // Test with https://localhost:5001/Privacy/?option=Hello
    public async Task Invoke(HttpContext httpContext)
    {
        var option = httpContext.Request.Query["option"];

        if (!string.IsNullOrWhiteSpace(option))
        {
            httpContext.Items["option"] = WebUtility.HtmlEncode(option);
        }

        await _next(httpContext);
    }
}

RequestSetOptionsMiddleware est configuré dans la classe RequestSetOptionsStartupFilter :

public class RequestSetOptionsStartupFilter : IStartupFilter
{
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        return builder =>
        {
            builder.UseMiddleware<RequestSetOptionsMiddleware>();
            next(builder);
        };
    }
}

IStartupFilter est inscrit dans le conteneur de service de ConfigureServices.

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
           .ConfigureAppConfiguration((hostingContext, config) =>
           {
           })
         .ConfigureWebHostDefaults(webBuilder =>
         {
             webBuilder.UseStartup<Startup>();
         })
        .ConfigureServices(services =>
        {
            services.AddTransient<IStartupFilter,
                      RequestSetOptionsStartupFilter>();
        });
}

Quand un paramètre de chaîne de requête pour option est fourni, le middleware traite l’affectation de valeur avant que le middleware ASP.NET Core n’affiche la réponse.

L’ordre d’exécution de l’intergiciel est défini par l’ordre des inscriptions d’IStartupFilter :

  • Plusieurs implémentations d’IStartupFilter peuvent interagir avec les mêmes objets. Si l’ordre est important, définissez l’ordre des inscriptions de leurs services IStartupFilter pour qu’il corresponde à l’ordre dans lequel leurs intergiciels doivent s’exécuter.

  • Les bibliothèques peuvent ajouter des intergiciels avec une ou plusieurs implémentations IStartupFilter qui s’exécutent avant ou après l’autre intergiciel d’application inscrit avec IStartupFilter. Pour appeler un middleware IStartupFilter avant un middleware ajouté par le IStartupFilter d’une bibliothèque :

    • Placez l’inscription du service avant l’ajout de la bibliothèque au conteneur de service.
    • Pour les appels suivants, placez l’inscription du service après l’ajout de la bibliothèque.

Ajouter la configuration au démarrage à partir d’un assembly externe

Une implémentation de IHostingStartup permet d’ajouter des améliorations à une application au démarrage à partir d’un assembly externe, en dehors de la classe Startup de l’application. Pour plus d’informations, consultez Utiliser des assemblys d’hébergement au démarrage dans ASP.NET Core.

Ressources supplémentaires