'AzureKeyVaultConfigurationProvider CancellationTokenSource has been disposed

I'm currently using IConfigurationBuilder.AddAzureKeyVault(keyVaultEndpoint, new DefaultAzureCredential()); to add Azure Key Vault secrets into my dotnet 6 application.

Whenever I resolve an instance of var configuration = serviceProvider.GetRequiredService<IConfiguration>(); I get a version of IConfiguration that I can use to access all keys across providers.

    public static T GetOptions<T>(this IServiceCollection services, string sectionName)
    where T : new()
    {
        using var serviceProvider = services.BuildServiceProvider();
        var configuration = serviceProvider.GetRequiredService<IConfiguration>();
        var section = configuration.GetSection(sectionName);
        var options = new T();
        section.Bind(options);

        return options;
    }

But when I leave the above method, the instance of IConfiguration apparently gets disposed and I receive the following exception:

at System.ThrowHelper.ThrowObjectDisposedException(ExceptionResource resource) at System.Threading.CancellationTokenSource.Cancel()
at Azure.Extensions.AspNetCore.Configuration.Secrets.AzureKeyVaultConfigurationProvider.Dispose(Boolean disposing) at Azure.Extensions.AspNetCore.Configuration.Secrets.AzureKeyVaultConfigurationProvider.Dispose() at Microsoft.Extensions.Configuration.ConfigurationManager.DisposeRegistrationsAndProvidersUnsynchronized() at Microsoft.Extensions.Configuration.ConfigurationManager.Dispose()
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.Dispose() at Microsoft.Extensions.DependencyInjection.ServiceProvider.Dispose()

I assume that IConfiguration is a singleton in the IServiceCollection, but why is getting disposed then. And why is the CancellationTokenSource NULL when disposing the object?



Solution 1:[1]

but why is getting disposed then

You are building and disposing the whole service provider which leads to disposing everything (what implements IDisposable) created/owned by it:

var services = new ServiceCollection();
services.AddSingleton<MyDisposable>(); 
// note that changing to services.AddSingleton(new MyDisposable()); will change behaviour of the program
var sp = services.BuildServiceProvider();
var myDisposable = sp.GetRequiredService<MyDisposable>();
sp.Dispose();
Console.WriteLine(myDisposable.Disposed); // prints True

public class MyDisposable : IDisposable
{
    public bool Disposed { get; set; }
    public void Dispose()
    {
        Disposed = true;
    }
}

In general you should avoid building ServiceProvider multiple times and should use existing APIs to get configuration where needed. But without rest of the code it is hard to tell how GetOptions should be changed/refactoried.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1