.Net Core Worker Service appsettings.json not being read

Viewed 3300

I created a .net core worker service, had IConfiguration injected into it so I can read a property from appsettings.json but everytime I run the file the property comes up as null. However if I force the IConfiguration to add a json file via the ConfigurationBuilder it works. How can I use the default settings to allow .net core worker service to read from appsettings?

public class ImageFileWatcher : IHostedService, IDisposable
{

    private readonly ILogger _logger;
    private readonly IConfiguration _configuration;
    FileSystemWatcher _watcher;

    public ImageFileWatcher(ILogger<ImageFileWatcher> logger, IConfiguration configuration)
    {
        _logger = logger;
        _configuration = configuration;
        // IConfigurationBuilder builder = new ConfigurationBuilder()
        // .AddJsonFile("appsettings.json")
        // .AddEnvironmentVariables();
        // this._configuration = builder.Build();
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {

        var watcherConfig = _configuration["WatcherConfig:filePath"];//this is where it comes up as null.
        _logger.LogInformation($"Image File watcher started on path{watcherConfig}");
        _watcher = new FileSystemWatcher(watcherConfig);
        _watcher.Created += OnNewImage;
        _watcher.EnableRaisingEvents = true;
        return Task.CompletedTask;
    }

Here is the appsettings.json file

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "WatcherConfig":{

    "filePath":"/Users/###/Documents/Development/ImageDrop"
  }
  
}

Here is the Program.cs file

public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostContext, configBuilder) =>
                {


                    configBuilder
                    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                    .AddJsonFile("appsettings.Production.json", optional: true, reloadOnChange: true)
                    .AddEnvironmentVariables(prefix: "ImageService_")
                    .Build();

                })
                .ConfigureServices((hostContext, services) =>
                {

                    services.AddHostedService<ImageFileWatcher>();

                });
    }

Here is the second attempt at the Program class:

public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)

                .ConfigureServices((hostContext, services) =>
                {
                    IConfiguration builder = new ConfigurationBuilder()
                     .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                    .AddJsonFile("appsettings.Production.json", optional: true, reloadOnChange: true)
                    .AddEnvironmentVariables(prefix: "ImageService_")
                    .Build();

                    hostContext.Configuration = builder;
                    services.AddHostedService<ImageFileWatcher>();

                });
    }
3 Answers

Given that you are using the default appsettings.json setup, the use of CreateDefaultBuilder() should mean you have nothing extra to configure.

There's a couple of notes which may help:

  • Remove any custom configuration setup as you don't need it (because of CreateDefaultBuilder)

  • Make sure that the appsettings.json file is copied to the build output. If not, in Visual Studio, you can right-click on the file and set "Copy to Output Directory" to "Copy if newer".

Alternatively, if you want to configure manually, note that:

  • When configuring the host, adding your config providers, you don't need to call the Build() method.

  • In your second example of Program the configuration is being set up in ConfigureServices, which is not where it should be. I guess this is why it was necessary to use the line hostContext.Configuration = builder which should not be required.

You must read App settings in Program.cs while building Host service. Check out what Host.CreateDefaultBuilder does, and if you decide to not use the default builder you might need to load the settings implicit.

If you heave further questions, please attach the Program.cs file, as the IConfiguration depends on its initialization not the usage in the service.

I've also faced this problem in a similar approach.

Glad "dotnet clean" and "dotnet build" worked for you.

Below, just wanna to contribute with a different solution.

  • Right button on appsettings.json > Properties > Copy to Output Directory > Copy always

  • Program


     static class Program
        {
            public static IConfigurationRoot Configuration { get; private set; }
    
            static async Task Main(string[] args)
            {
                using IHost host = CreateHostBuilder(args).Build();
    
            }
    
            static IHostBuilder CreateHostBuilder(string[] args) =>
              Host.CreateDefaultBuilder(args)
               .ConfigureAppConfiguration((hostingContext, configuration) =>
                {
                    configuration.Sources.Clear();
    
                    configuration
                            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
    
                    IConfigurationRoot configurationRoot = configuration.Build();
    
                    Configuration = configurationRoot;
                }).ConfigureServices((services) =>
                {
                    services.RegisterServices();
                });
        }

  • Created a class called AppSettings and other class called EndPoint to interact with appsettings.json data

    public class EndPoint
        {
            public string UrlWebApi { get; set; }
         }
    
        public class AppSettings
        {
            public EndPoint EndPoints { get; set; }
    
            public string Application { get; set; }
           
            public AppSettings()
            {
                IConfigurationBuilder builder = new ConfigurationBuilder();
    
                builder.AddJsonFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "appsettings.json"));
    
                var root = builder.Build();
    
                root.Bind(this);
            }
        }

  • Example of use of Appsettings class gettings URL from appsettings.json

    public class MyAppService : IMyAppService
        {
            private readonly AppSettings _appSettings;
            private readonly ILogger<MyAppService> _logger;
    
            public MyAppService(AppSettings appSettings, ILogger<MyAppService> logger)
            {
                _appSettings = appSettings;
                _logger = logger;
            }
    
            public async Task<string> ShowAppSettingsUse()
            {
                    _logger.LogInformation("Getting endpoint URL from AppSettings...");
    
                    var urlFromAppSettings = _appSettings.EndPoints.UrlWebApi;
    
                    return urlFromAppSettings;
            }
        }
    }
Related