Bind IConfigurationSection with refreshable config in console application without DI

Viewed 774

I'm having a problem making typed configuration refreshable in .Net Core Console Application.

The app will load typed objects from configuration...

{
     "LibrarySettings": {
       "SettingA": "ValueA",
       "SettingB": "ValueB"
     }
}

... and pass them down to libraries as IOption<SomeLibrarySettings>

public class LibrarySettings
{
    public string SettingA { get; set; }
    public string SettingB { get; set; }
}

public class BusinessLogic
{
    private IOptions<LibrarySettings> _settings;

    public BusinessLogic(IOptions<LibrarySettings> settings)
    {
        _settings = settings;
    }

    public string GetValueA => _settings.Value.SettingA;

    public string GetValueB => _settings.Value.SettingB;
}

During runtime if I change appsettings.json I will expect the underlying IOptions instance to update the values accordingly.

public class Program
{
    static void Main(string[] args)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", false, true);

        var configuration = builder.Build();

        LibrarySettings settings = new LibrarySettings();

        configuration.Bind("LibrarySettings", settings);

        BusinessLogic logic = new BusinessLogic(Options.Create(settings));

        while (true)
        {
            configuration.Reload();
            Console.WriteLine();
            Console.WriteLine(logic.GetValueA);
            Console.WriteLine(logic.GetValueB);
            Console.ReadLine();
        }
    }
}

Unfortunately that is not the case. When I launch this code and change the values in the copied over appsettings.json the values in the app don't get reloaded.

What am I doing wrong?

1 Answers

use IOptionsSnapshot insted of IOptions

public class BusinessLogic
{
     private IOptionsSnapshot<LibrarySettings> _settings;

     public BusinessLogic(IOptionsSnapshot<LibrarySettings> settings)
     {
         _settings = settings;
     }

     public string GetValueA => _settings.Value.SettingA;

     public string GetValueB => _settings.Value.SettingB;
 }

ref Options patterns in ASP.NET Core

EDIT: to avoid common error ('T' must be a non-abstract type with a public parameterless constructor)

public class LibrarySettings
{
    public string SettingA { get; set; }
    public string SettingB { get; set; }
    public LibrarySettings() {}
}

Got it to work:

class Program
    {

        static void Main(string[] args)
        {
            var builder = new ConfigurationBuilder()
                    .SetBasePath(Directory.GetCurrentDirectory())
                    .AddJsonFile("appsettings.json", false, true);

            var configuration = builder.Build();

            var settings = new LibrarySettings();

            configuration.GetSection("LibrarySettings").Bind(settings);

            var x = settings.SettingA;
        }

    }

    public class BusinessLogic
    {
        private LibrarySettings _settings;

        public BusinessLogic(IOptionsSnapshot<LibrarySettings> settings)
        {
            _settings = settings.Value;
        }

        public string GetValueA => _settings.SettingA;

        public string GetValueB => _settings.SettingB;
    }
    public class LibrarySettings
    {
        public string SettingA { get; set; }
        public string SettingB { get; set; }
        public LibrarySettings() { }
    }
Related