user584018
user584018

Reputation: 11304

trying to set config value `IHostBuilder` but not reflected for ConfigureServices in Startup class - asp.net core 3.1

I have below config with empty connection string,

"ConnString": {
"Value":  "" 
},

Now in Asp.Net Core 3.1 app I am trying to set the connection string value inside CreateHostBuilder

public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.ConfigureAppConfiguration((context, config) =>
                {
                    var settings = config.Build();
                    settings["ConnString:Value"] = "MY CONNECTION STRING";

                });

                webBuilder.UseStartup<Startup>();
            });

But this value is NOT reflected in ConfigureServices method of Startup class, it is still showing empty. What should I need to do here? please suggest!

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
    {
        var updateValue = Configuration.GetSection("ConnString:Value").Value;
    }

Upvotes: 4

Views: 4820

Answers (1)

pinkfloydx33
pinkfloydx33

Reputation: 12739

You are building the configuration and setting the value on the new IConfiguration object. However these settings will be lost as you aren't setting the values on the builder. The underlying infrastructure calls Build again later which creates another new IConfiguration. The values don't magically transfer over.

What you can do instead is call AddInMemoryCollection and pass your new settings there. This will then get consumed by the infrastructure and be made available later (ie in ConfigureServices):

webBuilder.ConfigureAppConfiguration((context, config) =>
{
   config.AddInMemoryCollection(
     new [] { 
       new KeyValuePair<string, string>("ConnString:Value", "MY CONNECTION STRING") 
     }
   );
});

IWebHostBuilder also has a UseSetting method where you can configure a single setting. This adds a new in-memory configuration provider containing just one value:

webBuilder.UseSetting("ConnString:Value", "MY CONNECTION STRING");

Note that the IWebHostBuilder will consume the configuration from the IHostBuilder (the generic host). You could alternatively call ConfigureAppConfiguration on the host builder instead.

Host.CreateDefaultBuilder(args) 
    .ConfigureAppConfiguration((context, config) =>
     {
        config.AddInMemoryCollection(
          new [] { 
            new KeyValuePair<string, string>("ConnString:Value", "MY CONNECTION STRING") 
          }
        );
     });

This "injection" is particularly useful if you have settings that are used to configure other settings. You could instead add them in ConfigureHostConfiguration (which doesn't exist for IWebHostBuilder) allowing their values to be available within ConfigureAppConfiguration on either builder.

Note that the configuration isn't shared back to the host builder. Any configuration you add to the web host doesn't automatically apply to the generic host. I call this out because it is different from the behavior of the ServiceCollection which is shared between the two (adding services to one adds to the other).

Update based on your comments:

I mentioned above that ConfigureHostConfiguration can be used if you have settings used to configure/setup other configuration providers. This is particularly useful for something like configuring Azure KeyVault.

Host.CreateDefaultBuilder(args) 
    .ConfigureHostConfiguration(config =>
     {
        // setup bootstrapping settings. For example if we need to add in values used
        // to configure azure key vault stored in app settings and maybe some in memory 
        config.AddJsonFile("appsettings.json");
        config.AddInMemoryCollection(
          new [] { 
            new KeyValuePair<string, string>("ClientId", "AzureClientId"), 
            new KeyValuePair<string, string>("TenantId", "AzureTenantId") 
          }
        );
     })
     // settings added in ConfigureHostConfiguration are now available via context.Configuration
    .ConfigureAppConfiguration((context, config) =>
     {
         // use the values we added during bootstrapping 
         var tenant = context.Configuration["TenantId"];
         var client = context.Configuration["ClientId"];
         // example, I don't remember the parameters off-hand
         config.AddAzureKeyVault(tenant, client, /*etc*/);
     });

In this example ConfigureAppConfiguration could also be called on the IWebHostBuilder instead.

For more information about configuration and the generic host, see the documentation.

Upvotes: 6

Related Questions