Skip to content

Instantly share code, notes, and snippets.

@noseratio
Created November 17, 2021 08:45
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save noseratio/cfb34f187ef7a8afd1e7650df306d11d to your computer and use it in GitHub Desktop.
Save noseratio/cfb34f187ef7a8afd1e7650df306d11d to your computer and use it in GitHub Desktop.
Generic .NET console app with DI and life cycle
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace ConsoleDisposable.Example
{
public class TransientDisposable : IDisposable
{
public void Dispose() => Console.WriteLine($"{nameof(TransientDisposable)}.Dispose()");
~TransientDisposable() =>
Console.WriteLine($"~{nameof(TransientDisposable)}!");
}
public class ScopedDisposable : IDisposable
{
public void Dispose() => Console.WriteLine($"{nameof(ScopedDisposable)}.Dispose()");
}
public class SingletonDisposable : IDisposable
{
public void Dispose() => Console.WriteLine($"{nameof(SingletonDisposable)}.Dispose()");
}
public class BgService: BackgroundService
{
readonly IHostApplicationLifetime _hostApplicationLifetime;
readonly ILogger<BgService> _logger;
public BgService(IHostApplicationLifetime hostApplicationLifetime, ILogger<BgService> logger)
{
_hostApplicationLifetime = hostApplicationLifetime;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
await Task.Delay(10000, stoppingToken);
}
catch (Exception ex) when (ex is OperationCanceledException)
{
_logger.LogInformation("Cancelled");
}
}
}
public class TimedHostedService : IHostedService, IDisposable
{
private int executionCount = 0;
private readonly ILogger<TimedHostedService> _logger;
private Timer _timer = null!;
public TimedHostedService(ILogger<TimedHostedService> logger)
{
_logger = logger;
}
public Task StartAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Timed Hosted Service running.");
_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromSeconds(5));
return Task.CompletedTask;
}
private void DoWork(object? state)
{
var count = Interlocked.Increment(ref executionCount);
_logger.LogInformation(
"Timed Hosted Service is working. Count: {Count}", count);
}
public Task StopAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Timed Hosted Service is stopping.");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
class Program
{
static async Task Main(string[] args)
{
var cts = new CancellationTokenSource(5000);
var builder = Host.CreateDefaultBuilder(args)
.ConfigureLogging(logging =>
{
//logging.ClearProviders();
logging.AddConsole();
})
.ConfigureServices((_, services) =>
services
.AddHostedService<BgService>()
.AddHostedService<TimedHostedService>()
.AddTransient<TransientDisposable>()
.AddScoped<ScopedDisposable>()
.AddSingleton<SingletonDisposable>())
.UseConsoleLifetime();
using IHost host = builder.Build();
ExemplifyDisposableScoping(host.Services, "Scope 1");
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, blocking: true);
Console.WriteLine();
ExemplifyDisposableScoping(host.Services, "Scope 2");
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, blocking: true);
Console.WriteLine();
try
{
await host.RunAsync(cts.Token);
}
catch (OperationCanceledException)
{
}
}
static void ExemplifyDisposableScoping(IServiceProvider services, string scope)
{
Console.WriteLine($"{scope}...");
using IServiceScope serviceScope = services.CreateScope();
IServiceProvider provider = serviceScope.ServiceProvider;
_ = provider.GetRequiredService<TransientDisposable>();
_ = provider.GetRequiredService<ScopedDisposable>();
_ = provider.GetRequiredService<SingletonDisposable>();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment