Skip to content

Configuring Services and Middleware in ASP.NET 6+ Without Startup.cs

Since .NET 6, Microsoft has streamlined the application startup process by unifying Program.cs and Startup.cs into a single file. This change simplifies the project structure but can be confusing for developers migrating from earlier versions.

The New Program.cs Structure

In .NET 6+, the Program.cs file now handles both service configuration and middleware pipeline setup:

csharp
var builder = WebApplication.CreateBuilder(args);

// Service configuration (formerly in Startup.ConfigureServices)
builder.Services.AddDbContext<ApplicationDbContext>(options => 
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

var app = builder.Build();

// Middleware configuration (formerly in Startup.Configure)
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();

Adding DbContext in .NET 6+

To register your DbContext in the new structure:

csharp
var builder = WebApplication.CreateBuilder(args);

// Add DbContext with SQL Server
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("YourConnectionString")));

// Add other services
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();
// ... rest of middleware configuration

Registering Different Service Lifetimes

The same service registration patterns from Startup.cs still apply:

csharp
// Transient services (created each time requested)
builder.Services.AddTransient<IEmailService, EmailService>();

// Scoped services (created once per request)
builder.Services.AddScoped<IUserRepository, UserRepository>();

// Singleton services (created first time requested)
builder.Services.AddSingleton<ICacheService, CacheService>();

Organizing with Extension Methods

For better code organization, you can create extension methods:

csharp
public static class ServiceExtensions
{
    public static void ConfigureDatabase(this IServiceCollection services, IConfiguration configuration)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(configuration.GetConnectionString("DefaultConnection")));
    }
    
    public static void ConfigureAuthentication(this IServiceCollection services, IConfiguration configuration)
    {
        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options => 
            {
                // JWT configuration
            });
    }
}

Then use them in Program.cs:

csharp
var builder = WebApplication.CreateBuilder(args);

builder.Services.ConfigureDatabase(builder.Configuration);
builder.Services.ConfigureAuthentication(builder.Configuration);

Recreating the Startup Class Pattern

If you prefer the traditional Startup class structure, you can recreate it:

csharp
public class Startup
{
    public IConfiguration Configuration { get; }
    
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }
    
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        
        services.AddControllers();
    }
    
    public void Configure(WebApplication app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseSwagger();
            app.UseSwaggerUI();
        }
        
        app.UseHttpsRedirection();
        app.UseAuthorization();
        app.MapControllers();
    }
}

Use it in Program.cs:

csharp
var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);

startup.ConfigureServices(builder.Services);

var app = builder.Build();
startup.Configure(app, app.Environment);

app.Run();

Migration Tips

TIP

When migrating from .NET 5 or earlier:

  1. Move service registrations from Startup.ConfigureServices() to builder.Services calls
  2. Move middleware configuration from Startup.Configure() to after var app = builder.Build()
  3. Update references from IConfiguration to builder.Configuration

WARNING

Ensure proper ordering of middleware calls. The sequence matters for authentication, authorization, and routing middleware.

The new unified Program.cs approach reduces boilerplate code while maintaining the same functionality. Choose the organization method that best fits your team's preferences and project complexity.