Anwendungsstart in ASP.NET Core

Von Kirk Larkin und Rick Anderson

ASP.NET Core-Apps, die mit den Webvorlagen erstellt wurden, enthalten den Anwendungsstartcode in der Datei Program.cs.

Der nachstehende App-Startcode unterstützt Folgendes:

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

Weitere Informationen zum Anwendungsstart finden Sie unter ASP.NET Core – Überblick über die Grundlagen.

Die Startup-Klasse konfiguriert Dienste und die Anforderungspipeline einer App.

Die Startup-Klasse

ASP.NET Core-Apps verwenden eine Startup-Klasse, die standardmäßig Startup genannt wird. Die Startup-Klasse:

  • Kann eine ConfigureServices-Methode enthalten, um die ConfigureServices der App zu konfigurieren. Ein Dienst ist eine wiederverwendbare Komponente, die App-Funktionalität bereitstellt. Dienste werden in registriert und in der App über Dependency Injection (DI) oder genutzt.
  • Enthält eine Configure-Methode, um die Anforderungsverarbeitungspipeline einer App zu erstellen.

ConfigureServices und Configure werden von der ASP.NET Core-Runtime aufgerufen, wenn die App gestartet wird:

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

Das Beispiel oben bezieht sich auf Pages. Die MVC-Version ist aber ähnlich.

Die Startup-Klasse wird angegeben, wenn der Startup der App erstellt wird. Die Startup-Klasse wird in der Regel durch Aufrufen der WebHostBuilderExtensions.UseStartup/<TStartup>-Methode für den Hostgenerator angegeben:

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

Der Host stellt Dienste für den Startup-Klassenkonstruktor bereit. Die App fügt über ConfigureServices zusätzliche Dienste hinzu. Sowohl die Host- als auch die App-Dienste sind in Configure und über die App verfügbar.

Bei Verwendung des Startup (IHostBuilder) können nur die folgenden Diensttypen in den Startup-Konstruktor eingefügt werden:

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
        {
        }
    }
}

Die meisten Dienste sind erst verfügbar, wenn die Configure-Methode aufgerufen wird.

Mehrere Startup-Klassen

Wenn die App unterschiedliche Startup-Klassen für unterschiedliche Umgebungen definiert (z.B. StartupDevelopment), wird zur Laufzeit die entsprechende Startup-Klasse ausgewählt. Die Klasse, deren Namenssuffix mit der aktuellen Umgebung übereinstimmt, wird priorisiert. Wenn die App in der Entwicklungsumgebung ausgeführt wird und sowohl eine Startup-Klasse als auch eine StartupDevelopment-Klasse enthält, wird die StartupDevelopment-Klasse verwendet. Weitere Informationen finden Sie unter Verwenden mehrerer Umgebungen.

Weitere Informationen zum Host finden Sie unter Der Host. Weitere Informationen zum Umgang mit Fehlern beim Start finden Sie unter Startup exception handling (Umgang mit Ausnahmen beim Start).

Die ConfigureServices-Methode

Die ConfigureServices-Methode:

  • Dies ist optional.
  • wird vor der Configure-Methode vom Host aufgerufen, um die App-Dienste zu konfigurieren.
  • Über diese Methode werden standardmäßig Konfigurationsoptionen festgelegt.

Es kann sein, dass der Host einige Dienste konfiguriert, bevor die Startup-Methoden aufgerufen werden. Weitere Informationen finden Sie unter Der Host.

Für Features, die ein umfangreiches Setup erfordern, sind in IServiceCollectionAdd{Service}-Erweiterungsmethoden verfügbar. Beispiel: AddDbContext, AddDefault, AddEntityFrameworkStores und AddPages:

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

Wenn Sie Dienste zum Dienstcontainer hinzufügen, können Sie auch über die App und die Configure-Methode auf diese zugreifen. Die Dienste werden über die Dependency Injection oder über aufgelöst.

Die Configure-Methode

Die Configure-Methode wird verwendet, um festzulegen, wie die App auf HTTP-Anforderungen reagiert. Sie können die Anforderungspipeline konfigurieren, indem Sie Middlewarekomponenten zu einer -Instanz hinzufügen. Die Configure-Methode kann auf IApplicationBuilder zugreifen, wird aber nicht im Dienstcontainer registriert. Über das Hosting wird ein IApplicationBuilder erstellt, der direkt an Configure übergeben wird.

Die ASP.NET Core-Vorlagen konfigurieren die Pipeline mit Unterstützung für:

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

Das Beispiel oben bezieht sich auf Pages. Die MVC-Version ist aber ähnlich.

Jede Use-Erweiterungsmethode fügt mindestens eine Middlewarekomponente zu der Anforderungspipeline hinzu. Beispielsweise konfiguriert UseStaticFilesUseStaticFiles für die Bereitstellung statischer Dateien.

Jede Middlewarekomponente in der Anforderungspipeline ist für das Aufrufen der jeweils nächsten Komponente in der Pipeline oder, wenn nötig, für das Kurzschließen der Kette zuständig.

In der Configure-Methodensignatur können außerdem auch zusätzliche Dienste wie IWebHostEnvironment, ILoggerFactory oder in ConfigureServices definierte Dienste angegeben werden. Diese Dienste werden eingefügt, wenn Sie verfügbar sind.

Weitere Informationen zur Verwendung von IApplicationBuilder und der Reihenfolge der Middlewareverarbeitung finden Sie unter IApplicationBuilder.

Konfigurieren von Diensten ohne Start

Rufen Sie die Hilfsmethoden ConfigureServices und Configure im Hostgenerator auf, um Dienste und die Anforderungsverarbeitungspipeline ohne die Startup-Klasse zu konfigurieren. Wenn ConfigureServices mehrmals aufgerufen wird, werden diese Aufrufe einander angefügt. Wenn es mehrere Aufrufe der Methode Configure gibt, wird der letzte Configure-Aufruf verwendet.

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"];
                });
            });
        });
}

Erweitern Sie den Start mit Startfiltern

Verwenden Sie IStartupFilter:

  • Um Middleware am Anfang und Ende der Configure-Middlewarepipeline einer App zu konfigurieren, ohne explizit aufzurufen. IStartupFilter wird von ASP.NET Core verwendet, um Standardwerte am Anfang der Pipeline hinzuzufügen, ohne dass der App-Autor die Standardmiddleware explizit registrieren lassen muss. IStartupFilter ermöglicht einer anderen Komponente den Aufruf von Use{Middleware} im Auftrag des App-Autors.
  • Um eine Pipeline aus Configure-Methoden zu erstellen. IStartupFilter.Configure kann festlegen, dass eine Middleware vor oder nach dem Hinzufügen von Middleware durch Bibliotheken ausgeführt wird.

IStartupFilter implementiert Configure. Das Element empfängt einen Action<IApplicationBuilder> und gibt diesen zurück. Eine IApplicationBuilder-Schnittstelle definiert Klassen, um die Anforderungspipeline einer App zu konfigurieren. Weitere Informationen finden Sie unter Erstellen einer Middlewarepipeline mit IApplicationBuilder.

Jeder IStartupFilter kann mindestens eine Middlewarekomponente in der Anforderungspipeline hinzufügen. Die Filter werden in der Reihenfolge aufgerufen, in der sie zum Dienstcontainer hinzugefügt wurden. Über Filter kann Middleware hinzugefügt werden, bevor oder nachdem dem nächsten Filter die Kontrolle erteilt wird. D.h., sie wird am Anfang oder am Ende einer App-Pipeline hinzugefügt.

Im folgenden Beispiel wird veranschaulicht, wie Middleware bei IStartupFilter registriert wird. Die RequestSetOptionsMiddleware-Middleware legt einen Optionswert über einen Parameter der Abfragezeichenfolge fest:

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

Die RequestSetOptionsMiddleware-Klasse wird in der RequestSetOptionsStartupFilter-Klasse konfiguriert:

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

Der IStartupFilter wird im Dienstcontainer in ConfigureServices registriert.

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

Wenn für option ein Parameter der Abfragezeichenfolge bereitgestellt wird, verarbeitet die Middleware die Wertzuweisung, bevor die ASP.NET Core-Middleware die Antwort rendert.

Die Reihenfolge der Ausführung der Middleware ist von der Reihenfolge der IStartupFilter-Registrierungen abhängig:

  • Es kann sein, dass mehrere Implementierungen von IStartupFilter mit denselben Objekten interagieren. Wenn die Reihenfolge für Sie wichtig ist, sollten Sie die IStartupFilter-Dienstregistrierungen der Implementierungen in der Reihenfolge anordnen, in der die Middleware ausgeführt werden soll.

  • Bibliotheken fügen möglicherweise Middleware mit mindestens einer IStartupFilter-Implementierung hinzu, die vor oder nach anderer App-Middleware ausgeführt wird, die über IStartupFilter registriert wurde. So rufen Sie IStartupFilter-Middleware auf, bevor eine Middleware durch den IStartupFilter von einer Bibliothek hinzugefügt wird:

    • Positionieren Sie die Dienstregistrierung, bevor die Bibliothek dem Dienstcontainer hinzugefügt wird.
    • Wenn sie danach aufgerufen werden soll, positionieren Sie die Dienstregistrierung, nachdem die Bibliothek hinzugefügt wurde.

Hinzufügen von Konfigurationen aus einer externen Assembly beim Start

Eine IHostingStartup-Implementierung ermöglicht das Hinzufügen von Erweiterungen zu einer App beim Start von einer externen Assembly außerhalb der Startup-Klasse der App aus. Weitere Informationen finden Sie unter Verwenden von Hostingstartassemblys in ASP.NET Core.

Zusätzliche Ressourcen