ASP.NET Core Startup Class Structure Explained: A Complete Guide to dotnet/aspnetcore

The ASP.NET Core Startup class consists of three essential parts—an optional constructor for dependency injection, a ConfigureServices method to register application services with the DI container, and a Configure method to build the HTTP request pipeline.

The Startup class serves as the central entry point that wires up an application’s services and request-processing pipeline in ASP.NET Core. According to the dotnet/aspnetcore source code, this architectural pattern separates service registration (application-wide) from request pipeline configuration (per-request), making applications composable and testable. Understanding the Startup class structure is essential for configuring middleware, dependency injection, and hosting options across different deployment scenarios.

The Three Core Components of an ASP.NET Core Startup Class

Constructor Injection (Optional)

The constructor accepts injected services such as IConfiguration or IWebHostEnvironment that are needed during startup. In src/Servers/Kestrel/samples/SampleApp/Startup.cs, the host injects these dependencies before calling the configuration methods, allowing conditional logic based on configuration settings or environment name.

ConfigureServices Method

This method registers services with the built-in DI container and runs once before any requests are processed. The canonical signature is:

public void ConfigureServices(IServiceCollection services)

As shown in src/DefaultBuilder/samples/SampleApp/Startup.cs, this is where you add MVC, Entity Framework Core, authentication, and other framework services. Advanced scenarios in src/Hosting/test/testassets/IStartupInjectionAssemblyName/Startup.cs demonstrate returning a custom IServiceProvider to replace the default container.

Configure Method

This method builds the HTTP request pipeline by adding middleware and executes to process requests. The common signature accepts IApplicationBuilder and additional services:

public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)

The implementation in src/Servers/Kestrel/samples/SampleApp/Startup.cs demonstrates how middleware like UseClientCertBuffering() is added to the pipeline. The IApplicationBuilder supplied is backed by the built service provider, allowing middleware to request services via app.ApplicationServices.

How the Host Invokes the Startup Class

The generic host processes the Startup class through four distinct phases:

  1. Host creationHostBuilder (or WebHostBuilder) calls UseStartup<Startup>() to specify the startup type.
  2. Instance creation – The host instantiates the Startup class, injecting any constructor parameters it can resolve from the service provider.
  3. Service registrationConfigureServices is invoked; all services added to IServiceCollection become available for constructor injection throughout the application.
  4. Pipeline building – After the service container is built, Configure runs. The IApplicationBuilder is backed by the built service provider, enabling middleware to resolve dependencies.

Implementation Examples from the aspnetcore Repository

Minimal Configuration (DefaultBuilder Sample)

The minimal implementation in src/DefaultBuilder/samples/SampleApp/Startup.cs demonstrates the essential structure with empty service registration and basic request handling:

public class Startup
{
    public void ConfigureServices(IServiceCollection services) { }

    public void Configure(IApplicationBuilder app, IConfiguration config)
    {
        app.Run(async ctx =>
        {
            await ctx.Response.WriteAsync($"Hello from {ctx.Request.GetDisplayUrl()}\r\n");
        });
    }
}

MVC and Environment-Specific Middleware

This pattern from the repository demonstrates conditional middleware based on IWebHostEnvironment injection:

public class Startup
{
    private readonly IWebHostEnvironment _env;

    public Startup(IWebHostEnvironment env) => _env = env;

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

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

        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseRouting();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

Custom Host Configuration with Kestrel

The full-featured sample in src/Servers/Kestrel/samples/SampleApp/Startup.cs includes a static Main method and custom Kestrel options:

public class Startup
{
    public void ConfigureServices(IServiceCollection services) { }

    public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
    {
        var logger = loggerFactory.CreateLogger("Default");
        app.UseClientCertBuffering();
        app.Run(async context => 
        { 
            // Request handling logic
        });
    }

    public static Task Main(string[] args)
    {
        var host = new HostBuilder()
            .ConfigureWebHost(web =>
            {
                web.UseKestrel((ctx, opts) =>
                {
                    opts.Listen(IPAddress.Loopback, 5000);
                    opts.ListenLocalhost(5001, l => l.UseHttps());
                })
                .UseStartup<Startup>();
            })
            .Build();

        return host.RunAsync();
    }
}

Additional reference implementations include HTTP/2 specific configuration in src/Servers/Kestrel/samples/Http2SampleApp/Startup.cs, IIS-integrated hosting in src/Servers/IIS/IISIntegration/samples/IISSample/Startup.cs, and MVC sandbox examples in src/Mvc/samples/MvcSandbox/Startup.cs.

Advanced Startup Patterns

Returning a Custom IServiceProvider

Advanced scenarios may replace the default dependency injection container by returning IServiceProvider from ConfigureServices. The test asset in src/Hosting/test/testassets/IStartupInjectionAssemblyName/Startup.cs demonstrates this pattern where the method signature becomes public IServiceProvider ConfigureServices(IServiceCollection services).

Configure Method Overloads

The Configure method can accept additional services directly as parameters—such as IConfiguration, ILoggerFactory, or IHostEnvironment—to avoid pulling them manually from the container. This pattern appears throughout the samples including src/Servers/Kestrel/samples/SampleApp/Startup.cs.

Summary

  • The ASP.NET Core Startup class consists of three logical parts: an optional constructor for dependency injection, ConfigureServices for registering application services, and Configure for building the middleware pipeline.
  • ConfigureServices runs once during application startup to populate the DI container, while Configure establishes the HTTP pipeline structure that executes per request.
  • The dotnet/aspnetcore repository demonstrates variations ranging from minimal startups in src/DefaultBuilder/samples/SampleApp/Startup.cs to complex configurations with custom Main methods and Kestrel options in src/Servers/Kestrel/samples/SampleApp/Startup.cs.

Frequently Asked Questions

Is the constructor required in an ASP.NET Core Startup class?

No, the constructor is optional. You only need it when your startup logic requires access to injected services like IConfiguration or IWebHostEnvironment before the configuration methods run. The host can instantiate the Startup class without a constructor if no initial dependencies are required.

What is the difference between ConfigureServices and Configure in the Startup class?

ConfigureServices registers application services with the dependency injection container and runs once at startup to build the service provider, while Configure builds the HTTP request pipeline by adding middleware and sets up the application to handle requests. The IApplicationBuilder passed to Configure is backed by the service provider built from ConfigureServices.

Can I replace the default dependency injection container in the Startup class?

Yes, ConfigureServices can return a custom IServiceProvider instead of void. This advanced pattern allows you to replace the built-in DI container with alternatives like Autofac or StructureMap, as demonstrated in test assets within the dotnet/aspnetcore repository at src/Hosting/test/testassets/IStartupInjectionAssemblyName/Startup.cs.

Where does the Configure method get its parameters from?

The host injects parameters into Configure from the service provider built after ConfigureServices runs. Common parameters include IApplicationBuilder, ILoggerFactory, IConfiguration, and IWebHostEnvironment, which are resolved automatically by the generic host without requiring manual lookup from the container.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →