Working with the IHostBuilder introduced to .netcore has been an overall pleasant experience… until I needed configuration from appsettings for app bootstrapping. Luckily, there’s still a way to do it!
The docs on
IHostBuilder are a good place to start if you’ve not worked with it before - though if you’ve found this post I’d imagine you have and are having the same struggle as me!
The idea of the
IHostBuilder is the place where you “set up” all the startup bits of the application - the “services” that are a part of it like WebHost, Orleans, Logging, IOC configuration, etc.
Here’s an example of what it can look like:
The above should be pretty straight forward, though I am setting some things “again” that the
CreateDefaultBuilder has already set - like logging and the loading of app settings, for example. What is the issue with the above? Well in my case, I needed a way to be able to change the port the web host was running on, depending on the environment.
There are ways to accomplish this with environment variables, as well as variables passed in the
args at application run, but I wanted to do it via configuration files. I needed a way to get configuration files “loaded and accessible” during the
First, we need a class that will represent our configuration, I’ve gone over a bit of this before in dotnet core console application IOptions configuration; see that for a refresher if needed.
In the above, sure we could have just use a “root” level property in our config, but I like doing it this way for getting a strongly typed
IOptions<T>, as well as demonstrating the fact you could do this with multiple properties via the strongly typed configuration object within your application bootstrapping.
So, why can’t we just do what we usually do and either inject the
IOptions<T> or get the service from our
IServiceProvider? The problem I was running into is the place where I’d need the
MyWebSiteConfig - under
ConfigureWebHostDefaults from the intro, has not yet actually “built” the configuration by ingesting the config files via
ConfigureAppConfiguration nor set up the services via
ConfigureServices. This can be confirmed by placing breakpoints in each section (
ConfigureServices) and observing that
ConfigureWebHostDefaults is the first breakpoint to hit, well before the things we need from configuration are actually loaded.
My initial thoughts were to just create two
HostBuilders, one to load the settings I need, get an instance of my
MyWebSiteConfig and pass it into a new
HostBuilder that will do (some) of the work again, but this time I’ll have access to what I need.
This seemed to work, aside from the fact that I got a few warnings that stated something to the effect of “don’t do this cuz singleton scoped things will be weird” - I don’t recall the exact warning (or was it error?), but I immediately went on to find another way to do it.
Thankfully, I found something promising IConfigurationBuilder.AddConfiguration. This extension method allows for that adding of an
IConfiguration onto an
IConfigurationBuilder. What does this mean? It means that I can do almost was I was working toward from “the problem” above, but rather than two separate
HostBuilders, we’ll use two separate
So what does our first
IConfiguration need to be made up of? We know we at least need the app settings files loaded, and a service provider that can return an instance of our
MyWebsiteConfig. That looks like this:
In the above I’m returning a named tuple with a
myWebsiteConfig. Much of this should look familiar:
- Get the environment name
- Create a temporary configuration builder
- Add the settings files to the builder using the environment
- get the
IConfigurationRootby building the
- Create a new service collection
- Configure the service for
- Build the
- Get the service from the
- Return the
Now that we actually have an instance of
MyWebsiteConfig, we are able to build our configuration dependent
In the above, we’re doing a lot of the same things as before, with just a few additions. First, our method signature is now receiving in addition to
args, the three items from our named tuple. We’re able to add our existing
configurationRoot onto the
IHostBuilder, as well as set the environment. Now, we are able to utilize our
myWebsiteConfig without having to worry about the ordering of the builder methods of
IHostBuilder, since we already have our instance of
MyWebsiteConfig prior to entering the method.
Here’s what it all looks like:
Running the app and breaking on the
UseUrls line you can see:
Code for this post can be found: https://github.com/Kritner-Blogs/Kritner.ConfigDuringBootstrapNetCore