C# – Where did Main() go?

When you create a new executable project in .NET 6, this is what you get (in a console app):

Console.WriteLine("Hello, World!");
Code language: C# (cs)

A single line of code. The Main() method is missing. This is due to the top-level statement feature added in C# 9. The stated purpose of this feature is to “minimize the amount of code you have to write.” OK, everyone uses project templates to create a new project though, right? So it’s not really minimizing the amount of code you have to write.

You’re not forced to use this top-level statement feature. If you like the structure provided by having Main() explicitly defined, you can create a project targeting .NET 5 and then switch it to .NET 6. I’ll show that below.

It’d be nice if there was a project template / setting to let you opt in to using this top-level statement approach, instead of it being the default requiring this workaround.

Create a .NET 6 project with a Main() method

First, create a new project targeting .NET 5:

New project targeting .NET 5

This will create the project with the Main() method:

using System; namespace ConsoleApp1 { internal class Program { static void Main(string[] args) { Console.WriteLine("Hello World!"); } } }
Code language: C# (cs)

Now switch to targeting .NET 6 by editing the .csproj file:

<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net6.0</TargetFramework> </PropertyGroup> </Project>
Code language: HTML, XML (xml)

That’s it. Quick and simple. Now you have a .NET 6 app with a Main() method.

ASP.NET – Main() and Startup are gone

The project template change is even bigger in ASP.NET. It combined the code from the Main() method and Startup class in a single top-level statement. If you like having Main() / Startup, you can create the project using .NET 5 and then switch to .NET 6 (same approach shown in the section above).

Here’s what the default ASP.NET project looks like with a top-level statement:

var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); var app = builder.Build(); // Configure the HTTP request pipeline. app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
Code language: C# (cs)

Compare this with the default project created in .NET 5 below, and decide for yourself which approach you prefer.

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 Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllers(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } }
Code language: C# (cs)

Leave a Comment