How I Do dotnet core App Setup Elegantly

Program.cs is usually one of the files that get quite messy after a while in every .NET project. From then, developers will add code on top of all that mess or even worse create a new class and reference that in.

Here’s a structure I found over years that helps me to keep app startup code readable and clean.

Generally there are 3 things to setup in Main function:

  1. Ingress appsettings and options (via appsettings files, environment variables or command line)
  2. Setup logging
  3. Setup ServiceProvider (dotnet core dependency injection)

I add Microsoft.Extensions.Hosting nuget package and use this in Main:

var hostBuilder = Host.CreateDefaultBuilder()
                   .ConfigureAppConfiguration(AddSettings)
                   .ConfigureServices(AddOptions)
                   .ConfigureServices(AddServices);
await builder.RunConsoleAsync();

CreateDefaultBuilder() creates and sets up all the 3 things above and return an IHostBuilder instance. IHostBuilder has couple of nice methods that accept lambda functions:

  • ConfigureAppConfiguration: to add configurations related to the app
  • ConfigureHostConfiguration: to add configurations related to the host itself (such as Kestrel, etc.)
  • ConfigureServices: add classes to DI

I leverage those and divide my app startup code in these three nice methods:

private static void AddSettings(IConfigurationBuilder configurationBuilder)
        {
            configurationBuilder
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddEnvironmentVariables();
        }

private static void AddServices(HostBuilderContext context, IServiceCollection serviceCollection)
        {
            serviceCollection
		.AddTransient<,>()
                .AddSingleton<>();
            
            serviceCollection.AddHostedService<>();
        }

private static void AddOptions(HostBuilderContext context, IServiceCollection serviceProvider)
        {
            var configuration = context.Configuration;
            
            serviceProvider.AddOptions<MyOptions>()
                .Bind(configuration.GetSection(nameof(MyOptions)))
                .ValidateDataAnnotations();
        }

So what benefits do I get?

  • Main method is clean and simple and shows the setup steps in high-level view
  • It uses Options pattern to have configurations as objects. This provides all compile time checks and intelisense features.
  • The amount of usage of stings is minimum. Therefore classes can be moved/renamed without worrying about app setup code.

What do you think?

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s