I'm at a loss here with why Dispose()
isn't being called when the program ends. I wrote a console application to facilitate testing an Azure Functions App. One of the classes implements IDisposable
but Dispose()
is never being called. I expanded my example to see if a dependent service that implements IDisposable
has it's Dispose()
method called and it does not. I just updated to 16.9.4 this morning and target framework is .NET 5. Here's the sample code:
public class CustomOptions
{
public const string Section = "CustomSettings";
public string Url { get; set; }
public bool UseHttps { get; set; }
}
public interface IDisposableService
{
void DoSomething();
}
public class DisposableService : IDisposableService, IDisposable
{
public void Dispose()
{
Console.WriteLine("Disposing a disposable service");
GC.SuppressFinalize(this);
}
public void DoSomething()
{
Console.WriteLine("I'm doing some work");
}
}
public interface IConsoleService
{
void Run(string[] args);
}
public class ConsoleService : IConsoleService, IDisposable
{
private readonly ILogger<ConsoleService> _logger;
private readonly CustomOptions _options;
private readonly IDisposableService _service;
public ConsoleService(IDisposableService service,
ILogger<ConsoleService> logger,
IOptions<CustomOptions> options)
{
_service = service;
_logger = logger;
_options = options.Value;
}
public void Dispose()
{
Console.WriteLine($"Disposing {nameof(ConsoleService)}");
GC.SuppressFinalize(this);
}
public void Run(string[] args)
{
_logger.LogInformation("The application is now starting {Start}", DateTime.Now);
Console.WriteLine($"The Url in the settings file is '{_options.Url}'");
_service.DoSomething();
}
}
class Program
{
static void Main(string[] args)
{
IHost host = Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
services.Configure<CustomOptions>(
context.Configuration.GetSection(CustomOptions.Section));
services.AddTransient<IDisposableService, DisposableService>();
services.AddTransient<IConsoleService, ConsoleService>();
services.AddLogging();
services.AddOptions();
})
.Build();
IConsoleService service =
ActivatorUtilities.CreateInstance<ConsoleService>(host.Services);
service.Run(args);
}
}
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Warning"
}
},
"CustomSettings": {
"Url": "www.contoso.com",
"UseHttps": true
}
}
The output from the program is:
info: ConsoleApp.ConsoleService[0]
The application is now starting 04/14/2021 10:30:54
The Url in the settings file is 'www.contoso.com'
I'm doing some work
Any help is greatly appreciated.
Changes to get it working are as follows:
IDisposable
to IConsoleService
public interface IConsoleService, IDisposable
{
void Run(string[] args);
}
ConsoleService
public class ConsoleService : IConsoleService
{
Wrap the IHost
variable in a using
statement or call host.Dispose()
Use IServiceProvider.GetService<>()
instead of ActivatorUtilities.CreateInstance<>()
host.Services.GetService<IConsoleService>().Run(args);
host.Dispose();
Here is an example just using the ServiceCollection
IServiceCollection services = new ServiceCollection();
services.AddSingleton<Application>(); // your application which implement RunAsync
using var serviceProvider = services.BuildServiceProvider();
await serviceProvider.GetService<Application>().RunAsync();