How to Handle the Startup Class When Migrating ASP.NET Core Projects

Cesar Aguirre - Sep 30 - - Dev Community

I originally posted this post on my blog a long time ago in a galaxy far, far away.


.NET 6.0 replaced the Startup class with a new hosting model and a simplified Program.cs file.

The Startup class is still available in newer versions. If we're migrating a pre-.NET 6.0 project, the .NET upgrade assistant tool does the work while keeping the Startup class.

Here are 3 alternatives to handle with the Startup class when migrating to newer versions:

1. Official Docs Approach

Newer versions of ASP.NET Core work perfectly fine with the old Program.cs file and Startup class, we can choose to do nothing and keep them.

Here's an old-style Program class:

using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace AnOldStyleAspNetCoreProject;

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>();
             });
}
Enter fullscreen mode Exit fullscreen mode

And a Startup class:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace AnOldStyleAspNetCoreProject;

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

    public IConfiguration Configuration { get; }

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

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseRouting();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}
Enter fullscreen mode Exit fullscreen mode

Nothing fancy. A simple API project.

If we want to keep the Startup class, here's what Microsoft official docs show to make the Startup class work with the new hosting model and the simplified Program.cs:

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();
Enter fullscreen mode Exit fullscreen mode

We created a new instance of Startup inside the new Program.cs file.

2. Hybrid Approach

If we really want to ditch the Startup class, Andrew Lock recommends a hybrid approach in his blog:

Turn the methods from the Startup class into private methods in the new Program.cs file.

var builder = WebApplication.CreateBuilder(args);

ConfigureServices(builder.Services);
// ๐Ÿ‘†๐Ÿ‘†๐Ÿ‘†

var app = builder.Build();

Configure(app, app.Environment);
// ๐Ÿ‘†๐Ÿ‘†๐Ÿ‘†

app.Run();

// This method ๐Ÿ‘‡ used to be in Startup.cs
static void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
}

// This method ๐Ÿ‘‡ used to be in Startup.cs too
static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseRouting();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}
Enter fullscreen mode Exit fullscreen mode

3. Do-It-Yourself Approach

And if we want our Program.cs to look like the newer ones, there's no automatic tool for that (at least I couldn't find one in my Googling session).

We have to copy the contents of the Startup class into the Program.cs file, by hand:

var builder = WebApplication.CreateBuilder(args);

// Put here ๐Ÿ‘‡ what you had in ConfigureServices...
builder.Services.AddControllers();

var app = builder.Build();

// Put here ๐Ÿ‘‡ what you had in Configure...
app.UseAuthorization();

// Before:
//
// app.UseRouting();
// ASP0014: Suggest using top level route registrations instead of UseEndpoints
//app.UseEndpoints(endpoints =>
//{
//    endpoints.MapControllers();
//});
//
// After:
app.MapControllers();

app.Run();
Enter fullscreen mode Exit fullscreen mode

We cut and pasted the content of Startup inside the right sections of the new Program.cs. This time, we get some warnings about deprecated methods and their alternatives.

Voilร ! If you're a lazy developer like me, do nothing or go with the approach from the official docs. Otherwise, go with any of the other two options.


Starting out or already on the software engineering journey? Join my free 7-day email course to refactor your coding career and save years and thousands of dollars' worth of career mistakes.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .