Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to reload appsettings.json at runtime each time it changes in .NET core 1.1 console application?

I attempted to reproduce the method described in this great article by Andrew Lock. However, I am unable to get this running in a .NET core 1.1 console application. When the appsettings.json file is changed and saved, the changes are not reflected in the application without restarting it.

There are multiple files involved, so I created the smallest example I could come up on github. I also provided details in the README.MD file on github.

Any help in resolving this would be most appreciated. Please keep in mind I am new to .NET core, and not an experienced developer. And this is my first question on stackoverflow... Thanks in advance!

like image 489
Roger Champagne Avatar asked Jul 12 '17 17:07

Roger Champagne


1 Answers

The key thing to understand is scope.

There are three scopes in ASP.NET Core - transient, scoped, and singleton. IOptionsSnapshot is configured as a scoped service.

In ASP.NET Core, a scope is started for every request, so every request, you would get a new instance of IOptionsSnapshot, with updated configuration values.

In the example you provided, you are creating an IServiceProvider, and are fetching an instance of IMyService directly from the top level provider:

IServiceCollection services = new ServiceCollection();
Startup startup = new Startup();
startup.ConfigureServices(services);
IServiceProvider serviceProvider = services.BuildServiceProvider();


while (true)
{
    var service = serviceProvider.GetService<IMyService>();
    var reply = service.DoSomething();

    Console.WriteLine(reply);
}

Essentially, you're always using the same scope for every request to the service provider, so you're always getting the same instance of IOptionsSnapshot. Effectively, if you never create a new scope, all of your scoped services become singletons!

The way to fix this is to create a new scope each time you fetch the service:

IServiceCollection services = new ServiceCollection();
Startup startup = new Startup();
startup.ConfigureServices(services);
IServiceProvider serviceProvider = services.BuildServiceProvider();


while (true)
{
    using (var scope = serviceProvider.CreateScope())
    {
        var service = scope.ServiceProvider.GetService<IMyService>();
        var reply = service.DoSomething();

        Console.WriteLine(reply);
    }
}

This also becomes important if you're doing things like creating an EF Core DbContext outside the context of a request in ASP.NET Core app (or in a console app). Always create a new scope before accessing services from the service provider!

P.S. I've created a pull request to fix your sample :)

like image 82
Sock Avatar answered Oct 24 '22 03:10

Sock