.NET Console Application Template

Here’s what I’ll use as the starting point for any new console application that I build. It includes simple logging to the console and to a file, dependency injection, and strongly typed configuration, including user secrets that don’t go to source control.


using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using MyApplication.Configuration;
using Serilog;
using Serilog.Debugging;
using System.Diagnostics;

// Writes Serilog errors do the debug window in case you're having trouble
// with your configuration.
SelfLog.Enable(msg => Debug.WriteLine(msg));

await Host.CreateDefaultBuilder(args)
    .ConfigureAppConfiguration((hostContext, builder) =>
        // Allows you to use the secrets.json file in
        // your user directory during development, so you don't
        // risk putting sensitive information into source control
    .ConfigureServices((hostContext, services) =>
        // Pulls the configuration information for Serilog 
        // logging into the default Serilog logger
        Log.Logger = new LoggerConfiguration()

        // Replaces the default logger with Serilog
        services.AddLogging(builder =>




using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MyApplication.Configuration;
using System.Text.Json;

partial class Program
    private readonly ILogger<Program> _logger;
    private readonly Config _config;

    // Injected logger and Config object
    public Program(ILogger<Program> logger, IOptions<Config> config)
        _logger = logger;
        _config = config.Value;

    public async Task ExecuteAsync()
        _logger.LogDebug("Config data: {configJson}",

        // Your real work goes here, probably a call to another class
        await DoSomethingAsync();

    private Task DoSomethingAsync()
        _logger.LogInformation(@"Your API password is {apiPassword}", _config.ApiPassword);
        _logger.LogInformation(@"Your item is {itemID}/{itemName}.",
            _config.Item.ID, _config.Item.Name);
        _logger.LogInformation(@"You have {numWidgets} widgets in your collection",
        return Task.CompletedTask;


  "ConfigStuff": {
    "Item": {
      "ID": 34,
      "Name": "Foo"

    "Collection": [
        "Color": "Blue",
        "Shape": "Circle"
        "Color": "Brown",
        "Shape": "Square"

    "ApiPassword": "This is overridden from the secrets.json file"

  "Serilog": {
    "Using": [
    "MinimumLevel": "Debug",
    "WriteTo": [
        "Name": "Console",
        "Args": {
          "restrictedToMinimumLevel": "Debug"
        "Name": "File",
        "Args": {
          "path": "C:/temp/log.txt",
          "rollingInterval": "Day",
          "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} [{Level}] [{SourceContext}] {Message}{NewLine}{Exception}",
          "restrictedToMinimumLevel": "Information"

secrets.json (in your user directory, not in the project directory)

  "ConfigStuff": {
    "ApiPassword": "mypassword"


<Project Sdk="Microsoft.NET.Sdk">


		<!-- Forces you to deal with compiler warnings -->
		<WarningsAsErrors />

		<!-- Auto-generated when you open
                     "Manage User Secrets" from the VS project -->

		<!-- These get injected into your generated AssemblyInfo class -->
		<Company>My Company Name</Company>
		<Product>My Product Name</Product>
		<AssemblyTitle>My Title</AssemblyTitle>


		<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="6.0.1" />
		<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
		<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
		<PackageReference Include="Serilog" Version="2.11.0" />
		<PackageReference Include="Serilog.Extensions.Logging" Version="3.1.0" />
		<PackageReference Include="Serilog.Settings.Configuration" Version="3.3.0" />
		<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
		<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />

		<None Update="appsettings.json">

Obviously, the below configuration classes would be specific to your application:


namespace MyApplication.Configuration;

public class Config
    public Item Item { get; init; } = new();
    public Widget[] Collection { get; init; } = Array.Empty<Widget>();
    public string ApiPassword { get; init; } = "";


namespace MyApplication.Configuration;

public class Item
    public int ID { get; init; }
    public string Name { get; init; } = "";


namespace MyApplication.Configuration;

public class Widget
    public string Color { get; init; } = "";
    public string Shape { get; init; } = "";

Leave a Reply

Your email address will not be published.