UPDATE: It appears that there’s now a “Worker Service” template available (thanks Hobby Developer) which scaffolds Dependency Injection, configuration and logging for you. If you wnat a long running service then that’s probably the best option but if you want an intermitantly triggered executable that does a defined task and then closes my solution is still probably preferable.

This is something that strangely doesn’t seem to be that well documented and took me a while to figure out though in the end it’s pretty simple.

All that’s required is to add the following NuGet packages and an appsettings.json file.

  • Microsoft.Extensions.Configuration
  • Microsoft.Extensions.Configuration.FileExtensions
  • Microsoft.Extensions.Configuration.Json
  • Microsoft.Extensions.DependencyInjection

The appsettings.json files “Copy to Output Directory” property should also be set to “Copy if newer” so that the application is able to access it when published.

Program.cs
class Program { public static IConfigurationRoot configuration; static int Main(string[] args) { // Initialize serilog logger Log.Logger = new LoggerConfiguration() .WriteTo.Console(Serilog.Events.LogEventLevel.Debug) .MinimumLevel.Debug() .Enrich.FromLogContext() .CreateLogger(); try { // Start! MainAsync(args).Wait(); return 0; } catch { return 1; } } static async Task MainAsync(string[] args) { // Create service collection Log.Information("Creating service collection"); ServiceCollection serviceCollection = new ServiceCollection(); ConfigureServices(serviceCollection); // Create service provider Log.Information("Building service provider"); IServiceProvider serviceProvider = serviceCollection.BuildServiceProvider(); // Print connection string to demonstrate configuration object is populated Console.WriteLine(configuration.GetConnectionString("DataConnection")); try { Log.Information("Starting service"); await serviceProvider.GetService<App>().Run(); Log.Information("Ending service"); } catch (Exception ex) { Log.Fatal(ex, "Error running service"); throw ex; } finally { Log.CloseAndFlush(); } } private static void ConfigureServices(IServiceCollection serviceCollection) { // Add logging serviceCollection.AddSingleton(LoggerFactory.Create(builder => { builder .AddSerilog(dispose: true); })); serviceCollection.AddLogging(); // Build configuration configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetParent(AppContext.BaseDirectory).FullName) .AddJsonFile("appsettings.json", false) .Build(); // Add access to generic IConfigurationRoot serviceCollection.AddSingleton<IConfigurationRoot>(configuration); // Add app serviceCollection.AddTransient<App>(); } }
appsettings.json
{ "EmailAddresses": [ "email1@test.com", "email2@test.com", "email3@test.com" ], "ConnectionStrings": { "DataConnection": "ConnectionStringToSQLDatabase" } }

An example of this in action can be seen here.

In the case of receiving the error “IConfigurationBuilder does not contain a definition for AddJsonFile” just rebuild the project and close and re-open Visual Studio.


2 Comments

jeonghwan · 5 March 2022 at 05:24

This good for me.

Ashutosh · 1 June 2022 at 07:59

You also need to install serilog nuget package.

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *