July 21, 2023

Startup For Dependency Injection, Settings and Logging

The Startup format for a Console program with a Serilog logger

You need quite a few packages:
    <PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="7.0.4" />
    <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
    <PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
    <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
    <PackageReference Include="Microsoft.Extensions.Logging.TraceSource" Version="7.0.0" />
    <PackageReference Include="Serilog" Version="2.12.0" />
    <PackageReference Include="Serilog.Enrichers.Environment" Version="2.2.0" />
    <PackageReference Include="Serilog.Extensions.Hosting" Version="7.0.0" />
    <PackageReference Include="Serilog.Extensions.Logging" Version="7.0.0" />
    <PackageReference Include="Serilog.Formatting.Compact" Version="1.1.0" />
    <PackageReference Include="Serilog.Settings.Configuration" Version="7.0.0" />
    <PackageReference Include="Serilog.Sinks.Async" Version="1.5.0" />
    <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
    <PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />

Here is a Startup class:

using System;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Console;
using Serilog;
using Serilog.Core;
using Serilog.Formatting.Compact;


public class Startup
{
  IConfigurationRoot? Configuration { get; init; }
 
  public AppSettings AppSettings { get; private set; } = new AppSettings();
 
  public Startup()
  {
     Configuration = BuildConfiguration();
  }
 
  public IServiceCollection ConfigureServices(string loggingFilePath)
  {
    IServiceCollection services = new ServiceCollection();
    services.AddLogging(builder => builder.AddSerilog(
        new LoggerConfiguration()
#if DEBUG
        .MinimumLevel.Debug() // Log Debug level and higher
#else
        .MinimumLevel.Information() // Log Information level and higher
#endif
        // To read the settings from the configuration file:
        //.ReadFrom.Configuration(this.Configuration!)
       .WriteTo.Console() // To make the console output window a logger sink
       // To write to a custom logging file and render object properties in JSon format
       .WriteTo.File(new RenderedCompactJsonFormatter(), loggingFilePath)
       .CreateLogger()));
 
    RegisterDependencyInjectedServices(services);
    return services;
  }
 
  private static IServiceCollection RegisterDependencyInjectedServices(IServiceCollection services)
  {
    // Use this format: services.AddScoped/Transient/Singleton<ISomething, Something>();
    // For example
    services.AddSingleton<IResDataRepo, ResDataRepo>();
    services.AddSingleton<ICnbDataRepo, CnbDataRepo>();
    services.AddTransient<IGuiInputListener, GuiListener>();    
    return services;
  }

  private IConfigurationRoot BuildConfiguration()
  {
     // To create a custom AppSetting file:
     const string settingsFileName = "{MyApplicationName}.AppSettings.json";
     string currentDirectory = Directory.GetCurrentDirectory();
     var builder = new ConfigurationBuilder()
          .SetBasePath(currentDirectory)
          .AddJsonFile(settingsFileName, optional: false);
     var config = builder.Build();
 
     var settings = config.GetSection("AppSettings").Get<AppSettings>();
     if (settings == null)
     {
         Console.WriteLine($"ERR: {settingsFileName} not found in current directory {currentDirectory}, using defaults!");
     }
     AppSettings = settings ?? new AppSettings();
     return config;
  }
}