Loading Config from Multiple Sources with .NET Core 2.x Web Api or MVC

Full source code available here.

.NET Core 2 and .NET Core 2.1 offer many ways to load configuration and they are well documented by Microsoft. But there is one scenario that I didn’t see explained.

If you want to supplement the configuration in appsettings.json with more from a remote service, database or some other source, you first need to know where that source is, then make a request to it and add it to your configuration. You are probably going to put the location of the remote configuration appsettings.json, then you call the remote config source. Sounds easy? It is, but not obvious.

First, a little background.

In an out of the box Web API or MVC application you get a Program.cs that looks like this -

 1public class Program
 2{
 3    public static void Main(string[] args)
 4    {
 5        CreateWebHostBuilder(args).Build().Run();
 6    }
 7
 8    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
 9        WebHost.CreateDefaultBuilder(args)
10            .UseStartup<Startup>();
11}

On line 9, we have WebHost.CreateDefaultBuilder(args), if you peek the definition of this with Resharper you will some something like -

The highlighted code is how your appsettings.json is loaded into the configuration and added to services collection, this call happens just as you leave Program.cs

But you want to read from the appsettings.json and use a value from it to make another call to get more configuration and then add the whole lot of the services collection. You might also want to setup some logging configuration in Program.cs, so you need access to all configuration settings before calling

CreateWebHostBuilder(args).Build().Run();

Here’s how you do it.

Step 1

Inside the main method in Program.cs, build the configuration yourself -

1IConfigurationBuilder builder = new ConfigurationBuilder()
2    .AddJsonFile("appsettings.json");
3Configuration = builder.Build();

Get the location of the other configuration service, in my example it is another json file. Add it to the builder and call build.

1string otherConfigService = Configuration["otherConfigService"]; // this could be a database or something like consul
2
3builder.AddJsonFile(otherConfigService);
4Configuration = builder.Build();

Now you have access to the configuration values from the second source.

1Configuration["SomeOtherConfigItem1"]}
2Configuration["SomeOtherConfigItem2"]}

So far so good, but as mentioned above, the CreateDefaultBuilder adds the configuration to the ServiceCollection, making it available by DI. But that only happens for appsettings.json (and appsettings.{env.EnvironmentName}.json, not the config you loaded from the other source.

If you tried to access the a config setting of your from inside Startup.cs or a controller, it would not be there.

Step 2

Let’s make our configuration available via the ServicesCollection.

In the first block of code above there was a call - CreateWebHostBuilder(args).Build().Run();

I added line 4 below, this will add the configuration to the services collection.

1public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
2    WebHost.CreateDefaultBuilder(args)
3        .UseStartup<Startup>()
4        .UseConfiguration(Configuration); // add this line to add your configuration to the service collection

For clarity, here is the full listing of Program.cs.

 1public class Program
 2{
 3    private static IConfiguration Configuration { get; set; }
 4    public static void Main(string[] args)
 5    {
 6        var builder = new ConfigurationBuilder()
 7            .AddJsonFile("appsettings.json");
 8        Configuration = builder.Build();
 9        string otherConfigService = Configuration["otherConfigService"]; // this could be a database or something like consul
10
11        builder.AddJsonFile(otherConfigService);
12        Configuration = builder.Build();
13        Debug.WriteLine($"Configuration[\"SomeOtherConfigItem1\"] = {Configuration["SomeOtherConfigItem1"]}");
14        Debug.WriteLine($"Configuration[\"SomeOtherConfigItem2\"] = {Configuration["SomeOtherConfigItem2"]}");
15
16        CreateWebHostBuilder(args).Build().Run();
17    }
18
19    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
20        WebHost.CreateDefaultBuilder(args)
21            .UseStartup<Startup>()
22            .UseConfiguration(Configuration); // add this line to add your configuration to the service collection
23}

Now, the config values loaded from appsettings.json and your secondary config source will be available throughout your application.  
Full source code available here.

comments powered by Disqus

Related