Dependency Injection with Generic Host & Default HostBuilder
Example With a Hosted Service
public class Program
{
public static async Task Main(string[] args)
{
await Host.CreateDefaultBuilder(args)
// Set the ContentRoot to the path of the executing assembly:
.UseContentRoot(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))
.ConfigureServices((hostContext, services) =>
{
services
.AddHostedService<ConsoleService>();
// IHostedService has full access to the DI container:
.AddSingleton<IWeatherService, WeatherService>();
services.AddOptions<WeatherSettings>()
.Bind(hostContext.Configuration.GetSection("Weather"));
})
.RunConsoleAsync();
}
}
internal sealed class ConsoleHostedService : IHostedService
{
private int? _exitCode;
private readonly ILogger _logger;
private readonly IHostApplicationLifetime _appLifetime;
private readonly IWeatherService _weatherService;
public ConsoleHostedService(
ILogger<ConsoleHostedService> logger,
IHostApplicationLifetime appLifetime,
IWeatherService weatherService)
{
_logger = logger;
_appLifetime = appLifetime;
_weatherService = weatherService;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_appLifetime.ApplicationStarted.Register(() =>
{
Task.Run(async () =>
{
try
{
IReadOnlyList<int> temperatures = _weatherService.GetFiveDayTemperaturesAsync();
_exitCode = 0;
}
catch (Exception ex)
{
_exitCode = 1;
}
finally
{
// Stop the application once the work is done
_appLifetime.StopApplication();
}
});
});
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
// Optionally, you can set the exit code here:
Environment.ExitCode = _exitCode.GetValueOrDefault(-1);
return Task.CompletedTask;
}
}
WeatherService.cs
internal sealed class WeatherService : IWeatherService
{
private readonly ILogger<WeatherService> _logger;
private readonly IOptions<WeatherSettings> _weatherSettings;
public WeatherService(ILogger<WeatherService> logger, IOptions<WeatherSettings> weatherSettings)
{
_logger = logger;
_weatherSettings = weatherSettings;
}
public async Task<IReadOnlyList<int>> GetFiveDayTemperaturesAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Fetching weather...");
// Simulate some network latency
await Task.Delay(2000, cancellationToken);
int[] temperatures = new[] { 76, 76, 77, 79, 78 };
if (_weatherSettings.Value.Unit.Equals("C", StringComparison.OrdinalIgnoreCase))
{
for (int i = 0; i < temperatures.Length; i++)
{
temperatures[i] = (int)Math.Round((temperatures[i] - 32) / 1.8);
}
}
_logger.LogInformation("Fetched weather successfully");
return temperatures;
}
}
WeatherSettings.cs
internal sealed class WeatherSettings
{
public string Unit { get; set; }
}
appsettings.Json
{
"Logging":
{
"LogLevel":
{
"Default": "Debug",
// Avoid logging lifetime events
"Microsoft.Hosting.Lifetime": "Warning",
// Avoid logging Host internal events
"Microsoft.Extensions.Hosting.Internal.Host": "Warning"
}
},
"Weather":
{
"Unit": "C"
}
}