ASP.NET Core 8 Startup File Configuration
Problem
When migrating ASP.NET MVC applications from .NET Framework to .NET 8, developers encounter significant changes in the application startup pattern. Key questions arise:
- Does ASP.NET Core 8 still use the OWIN-style
Startup.cs
file? - If not, how do you configure elements like authentication/authorization and middleware?
- Where should services and request pipeline configuration go in modern ASP.NET Core?
This transition presents challenges for developers accustomed to the traditional startup class pattern.
Solution
ASP.NET Core 8 introduces two configuration approaches:
- Unified
Program.cs
(Recommended Default)
All configuration happens in a singleProgram.cs
file - Traditional
Startup.cs
Class
Maintains separation between service configuration and HTTP pipeline setup
Option 1: Modern Unified Configuration (Program.cs)
var builder = WebApplication.CreateBuilder(args);
// Service Configuration
builder.Services.AddControllersWithViews();
// Configure Authentication (OAuth Example)
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = "Cookies";
options.DefaultSignInScheme = "Cookies";
options.DefaultChallengeScheme = "Google";
})
.AddCookie()
.AddGoogle(options =>
{
options.ClientId = builder.Configuration["Authentication:Google:ClientId"];
options.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"];
});
var app = builder.Build();
// Middleware Pipeline Configuration
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
// Authentication & Authorization Middleware
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Key aspects of this approach:
- Services registered via
builder.Services
collection - Middleware configured through
app
object methods - No separate
Startup
class required - Clean flow from services → build → middleware pipeline
Option 2: Traditional Startup Class
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>();
});
}
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
// OAuth Configuration
services.AddAuthentication(options => { /* ... */ })
.AddCookie()
.AddGoogle(options =>
{
options.ClientId = Configuration["Authentication:Google:ClientId"];
options.ClientSecret = Configuration["Authentication:Google:ClientSecret"];
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (!env.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
Key Differences
Feature | Unified Program.cs | Startup Class |
---|---|---|
File Structure | Single file | Two files |
Project Templates | Default in .NET 6-8 | Legacy format |
Configuration Access | builder.Configuration | Constructor injection |
Middleware Registration | Directly on app object | In Configure method |
Service Registration | Before var app = builder.Build() | In ConfigureServices method |
Separation of Concerns | Moderate | High |
Migration Recommendations
New Projects
Use unifiedProgram.cs
approach - it's streamlined and reflects current best practicesExisting Applications
- Gradually migrate from
Startup.cs
to unified approach - Create extension methods to maintain organization:cs
// In Program.cs builder.Services.AddCustomAuthentication(); builder.Services.AddDatabaseServices(); // In separate files public static class ServiceExtensions { public static void AddCustomAuthentication(this IServiceCollection services) { services.AddAuthentication()...; } }
- Gradually migrate from
Authentication Setup
- Modern authentication uses
AddAuthentication()
+Add[Provider]()
pattern - OWIN/Katana-specific code needs replacement
- Configuration-based setup recommended:
json"Authentication": { "Google": { "ClientId": "YOUR_CLIENT_ID", "ClientSecret": "YOUR_CLIENT_SECRET" } }
- Modern authentication uses
Important Considerations
Placement Matters
Ensure authentication middleware appears:
- After
UseRouting()
- Before
UseAuthorization()
- Before endpoint mapping (
MapControllers()
/MapRazorPages()
)
Authorization Sequence
app.UseRouting();
app.UseAuthentication(); // Must come first
app.UseAuthorization(); // Follows authentication
OAuth Flow Changes
ASP.NET Core handles OAuth differently than OWIN:
- Different authentication middleware APIs
- Revised authorization policy system
- Token management changes
When to Use Each Approach
Choose Unified
Program.cs
When- Starting a new project
- Building microservices
- Creating small-to-medium applications
- Wanting minimal ceremony
Choose Startup Class When
- Migrating large existing applications
- Requiring deep organization of configuration
- Working with legacy packages requiring startup class
- Needing explicit separation of service/pipeline concerns
Conclusion
ASP.NET Core 8 offers flexibility in startup configuration:
- Unified
Program.cs
is the modern default for new projects - Traditional `Startup.cs remains supported for migration scenarios
For OAuth and service configuration, both patterns support:
- Adding authentication via
AddAuthentication()
- Setting up providers like Google, Facebook, etc.
- Configuring middleware ordering
The default project templates now generate the unified approach, reflecting Microsoft's recommendation for new development. Migrating applications should focus on porting startup logic while accounting for authentication model changes.