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.
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>();
}
}
{
"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 5:24 am
This good for me.
Ashutosh · 1 June 2022 at 7:59 am
You also need to install serilog nuget package.