Read appsettings.json in Main Program.cs
Asked Answered
S

10

100

First of all my main purpose is to setup the IP and Port for my application dynamically.

I'm using IConfiguration to inject a json config file, like some tutorial mentioned.

However, I can't retrieve the configuration in Program.cs, because my WebHostBuilder will use the StartUp and Url at the same time.

So at the time the host build up, there is nothing in my configuration.

WebProtocolSettings settings_Web = new WebProtocolSettings();
var host = new WebHostBuilder()
                .UseIISIntegration()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseStartup<Startup>()
                .UseUrls(settings_Web.Url + ":" + settings_Web.Port)
                .Build();

In Startup.cs

public Startup(IHostingEnvironment env)
{
    // Set up configuration sources.
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);

    Configuration = builder.Build();
}

public IConfigurationRoot Configuration { get; set; }

public void ConfigureServices(IServiceCollection services)
{
    // Adds services required for using options.
    services.AddOptions();

    var _WebProtocolSettings = Configuration.GetSection("WebProtocolSettings");

    // Register the IConfiguration instance
    services.Configure<WebProtocolSettings>(_WebProtocolSettings);
}

My appsettings.json:

{
    "WebProtocolSettings": {
        "Url": "127.0.0.1",
        "Port": 5050
    }
}

My WebProtocolSettings.cs:

public class WebProtocolSettings
{
    public string Url { get; set; }
    public int Port { get; set; }
}
Sellars answered 19/1, 2017 at 9:54 Comment(0)
N
114

Update .Net 6

It's now easy to get any settings from the ConfigurationManager by calling the GetValue<type>(string key) extension method. You can also use Index(string key) to return a string. See this answer.


You must build a configuration in your main method, get the section and bind it to your model. No way around it.

public static void Main(string[] args)
{
    var config = new ConfigurationBuilder()
        .AddJsonFile("appsettings.json", optional: false)
        .Build();

    WebProtocolSettings settings_Web = new WebProtocolSettings();
    config.GetSection("WebProtocolSettings").Bind(settings_Web);

    var host = new WebHostBuilder()
            .UseIISIntegration()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseStartup<Startup>()
            .UseUrls(settings_Web.Url + ":" + settings_Web.Port)
            .Build()

    host.Run();
}

##Update

An alternative way of doing it is by passing the configuration to UseConfiguration as described in the

public static void Main(string[] args)
{
    var config = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("hosting.json", optional: true)
        .AddCommandLine(args)
        .Build();

    var host = new WebHostBuilder()
        .UseUrls("http://*:5000")
        .UseConfiguration(config)
        .UseKestrel()
        .Configure(app =>
        {
            app.Run(context => 
                context.Response.WriteAsync("Hello, World!"));
        })
        .Build();

    host.Run();
}

or in ASP.NET Core > 2.0

public static void Main(string[] args)
{
    BuildWebHost(args).Run();
}

public static IWebHost BuildWebHost(string[] args)
{
    var config = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("hosting.json", optional: true)
        .AddCommandLine(args)
        .Build();

    return WebHost.CreateDefaultBuilder(args)
        .UseUrls("http://*:5000")
        .UseConfiguration(config)
        .Configure(app =>
        {
            app.Run(context => 
                context.Response.WriteAsync("Hello, World!"));
        })
        .Build();
}
Nanny answered 19/1, 2017 at 9:59 Comment(8)
Hi @Tseng, thank you for your answer, however, how do I archive the path for "appsettings.json" in Main Program.cs?Sellars
It has to be in the same folder as the application. Same rules apply when you call it within the startup classNanny
I found the ways: .SetBasePath(Directory.GetCurrentDirectory()). Also, should be config.GetSection not , Configuration.GetSection. Thank you for your helpSellars
@Nanny what If you need to access hostingContext.HostingEnvironment.EnvironmentName because you have environment specific hosting.json files?Earlineearls
Note that when configured this way the configuration won't be updated when the JSON files are changed at runtime. I posted an alternative that works around this.Mirianmirielle
To add to the complexity of the question, how does it read the configuration specific to the environment, appsettings-${ENVIRONMENT}.json?Hydrodynamics
Will this solution still work when deployed. For example will the app settings in the Json be overridden by the app settings found in the app service?Concepcionconcept
@DanCundy: (Azure) App Service values are set via environment variables, so you would have to add .AddEnvironmentVariables(). The order of the AddXxx is the order in which will be overridden (latest key wins, so what ever is registered last will override previous one - if it has a specific key defined). But these days you have Generic Host for easy bootstrapping of console running servicesNanny
P
130

In .NET 6

var builder = WebApplication.CreateBuilder(args);

// Using the GetValue<type>(string key) method
var configValue = builder.Configuration.GetValue<string>("Authentication:CookieAuthentication:LoginPath");

// or using the index property (which always returns a string)
var configValue = builder.Configuration["Authentication:CookieAuthentication:LoginPath"];
Phlebotomy answered 17/12, 2021 at 11:16 Comment(2)
Thanks, exactly what I needed. Should be on the top as most other answers are outdated.Ultracentrifuge
Which is also written var configValue = builder.Configuration["Authentication:CookieAuthentication:LoginPath"];Earful
N
114

Update .Net 6

It's now easy to get any settings from the ConfigurationManager by calling the GetValue<type>(string key) extension method. You can also use Index(string key) to return a string. See this answer.


You must build a configuration in your main method, get the section and bind it to your model. No way around it.

public static void Main(string[] args)
{
    var config = new ConfigurationBuilder()
        .AddJsonFile("appsettings.json", optional: false)
        .Build();

    WebProtocolSettings settings_Web = new WebProtocolSettings();
    config.GetSection("WebProtocolSettings").Bind(settings_Web);

    var host = new WebHostBuilder()
            .UseIISIntegration()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseStartup<Startup>()
            .UseUrls(settings_Web.Url + ":" + settings_Web.Port)
            .Build()

    host.Run();
}

##Update

An alternative way of doing it is by passing the configuration to UseConfiguration as described in the

public static void Main(string[] args)
{
    var config = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("hosting.json", optional: true)
        .AddCommandLine(args)
        .Build();

    var host = new WebHostBuilder()
        .UseUrls("http://*:5000")
        .UseConfiguration(config)
        .UseKestrel()
        .Configure(app =>
        {
            app.Run(context => 
                context.Response.WriteAsync("Hello, World!"));
        })
        .Build();

    host.Run();
}

or in ASP.NET Core > 2.0

public static void Main(string[] args)
{
    BuildWebHost(args).Run();
}

public static IWebHost BuildWebHost(string[] args)
{
    var config = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("hosting.json", optional: true)
        .AddCommandLine(args)
        .Build();

    return WebHost.CreateDefaultBuilder(args)
        .UseUrls("http://*:5000")
        .UseConfiguration(config)
        .Configure(app =>
        {
            app.Run(context => 
                context.Response.WriteAsync("Hello, World!"));
        })
        .Build();
}
Nanny answered 19/1, 2017 at 9:59 Comment(8)
Hi @Tseng, thank you for your answer, however, how do I archive the path for "appsettings.json" in Main Program.cs?Sellars
It has to be in the same folder as the application. Same rules apply when you call it within the startup classNanny
I found the ways: .SetBasePath(Directory.GetCurrentDirectory()). Also, should be config.GetSection not , Configuration.GetSection. Thank you for your helpSellars
@Nanny what If you need to access hostingContext.HostingEnvironment.EnvironmentName because you have environment specific hosting.json files?Earlineearls
Note that when configured this way the configuration won't be updated when the JSON files are changed at runtime. I posted an alternative that works around this.Mirianmirielle
To add to the complexity of the question, how does it read the configuration specific to the environment, appsettings-${ENVIRONMENT}.json?Hydrodynamics
Will this solution still work when deployed. For example will the app settings in the Json be overridden by the app settings found in the app service?Concepcionconcept
@DanCundy: (Azure) App Service values are set via environment variables, so you would have to add .AddEnvironmentVariables(). The order of the AddXxx is the order in which will be overridden (latest key wins, so what ever is registered last will override previous one - if it has a specific key defined). But these days you have Generic Host for easy bootstrapping of console running servicesNanny
M
5

.UseConfiguration (Tseng's alternative answer) is the simplest way, but note that when configured this way changes made to the configuration files at runtime are not applied to your IConfiguration objects. To keep the configuration dynamic you have to use .ConfigureAppConfiguration - but then you have to build the configuration an extra time for use in Main(). You can re-use the code that configures it, however.

ASP.NET Core 2.2:

    public static void Main(string[] args)
    {
        IConfigurationBuilder configBuilderForMain = new ConfigurationBuilder();
        ConfigureConfiguration(configBuilderForMain);
        IConfiguration configForMain = configBuilderForMain.Build();

        // ... use configForMain to read config here ...

        var host = new WebHostBuilder()
            .ConfigureAppConfiguration(ConfigureConfiguration)
            // ... the rest of it ...
            .Build();
    }

    public static void ConfigureConfiguration(IConfigurationBuilder config)
    {
        config.SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
    }
Mirianmirielle answered 17/5, 2019 at 9:53 Comment(0)
A
4

In asp.net core 3.1, you can access configuration through the hostContext. This sample is based on the Worker Service Project:

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) =>
                {
                    //Access configuration here with the Host Context.  For example, to get a connection string from AppSettings.json:
                    var connectionString = hostContext.Configuration.GetConnectionString("MyConnectionString");
                    services.AddHostedService<Worker>();
                });
    }
Ahead answered 18/4, 2021 at 20:35 Comment(2)
ConfigureServises is called AFTER ConfigureWebHostDefaults is called. So this will not help in this case.Betel
exactly what I was looking for.Inspired
T
3

An old question with some new answers, so this is how I like to do it.

  1. Define the config in appsettings.json

         "ServiceConfig": { "PortNumber": 5005 },
    
  2. Create a class for the config:

         public class ServiceConfig
         {
             private readonly IConfiguration configuration;
             public const string SectionName = "ServiceConfig";
             public ServiceConfig(IConfiguration config)
             {
                 configuration = config;            
                 configuration.GetSection(SectionName).Bind(this);            
             }
             public int PortNumber { get; set; }
         }
    
  3. In Program.cs use the config:

         var config = new ServiceConfig(builder.Configuration);
         builder.WebHost.UseUrls($"http://*:{config.PortNumber}");
    

This method has the added benefit of being able to be used as a service too for dependency injection:

         builder.Services.AddSingleton<ServiceConfig>();
Tireless answered 5/7, 2022 at 22:49 Comment(0)
K
2

The method with the support for command line arguments and default appsettings files:

public static class Configuration
{
    public static IConfigurationRoot BuildConfigurationRoot()
    {

        var args = Environment.GetCommandLineArgs();
        var envArg = Array.IndexOf(args, "--environment");
        var envFromArgs = envArg >= 0 ? args[envArg + 1] : null;

        var aspnetcore = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
        var dotnetcore = Environment.GetEnvironmentVariable("DOTNET_ENVIRONMENT");

        var environment = envFromArgs ?? (string.IsNullOrWhiteSpace(aspnetcore)
            ? dotnetcore
            : aspnetcore);

        var configuration = new ConfigurationBuilder()
            .AddCommandLine(Environment.GetCommandLineArgs())
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddJsonFile(
                $"appsettings.{environment}.json",
                optional: true)
            .Build();

        return configuration; 
    }
}
Krissy answered 18/9, 2020 at 9:32 Comment(2)
Might you want to include ".AddEnvironmentVariables()" as a line prior to .Build() ?Collusion
There is a minor error with the IndexOf() method. This method is a static method in the Array class. So instead of args.IndexOf(), you need to use the Array.IndexOf("--environment");. An instance of an array cannot be used to access the IndexOf static method.Hydromechanics
Y
2

In .NET 7 you need to use the BuildServiceProvider()

So the top of your program.cs will look something like this;

var builder = WebApplication.CreateBuilder(args);
var provider = builder.Services.BuildServiceProvider();
var _configuration = provider.GetRequiredService<IConfiguration>();

And then you can access your appsettings.json values like so;

var configVal = _configuration.GetSection("Foo").GetValue<string>("Bar");
Yugoslavia answered 2/2, 2023 at 14:34 Comment(1)
With the latest package .NET 7 it should be: var builder = WebAssemblyHostBuilder.CreateDefault(args); var configVal = builder.Configuration.GetSection("Foo").GetValue<string>("Bar");Oh
P
0

.NET 8

Given appsettings.json file:

{
  "MySettings": {
    "Name": "Bob",
    "Counter": "100",
  }
}

And MySettings class:

public class MySettings
{
    public string? Name { get; set; }
    public int? Counter { get; set; }
}

Read those values in Program.cs file:

var builder = WebApplication.CreateBuilder(args);
var mySettings = new MySettings();
builder.Configuration.GetRequiredSection(nameof(MySettings)).Bind(mySettings);

var name = mySettings.Name; // Bob
var counter = mySettings.Counter; // 100
Paulina answered 23/2 at 10:54 Comment(0)
E
-3

In .net core 3.1 you can use ConfigurationHelper.GetConfiguration() to get appSetting variables:

appSettings.json

"Endpoint": {
"ip": "170.888.88.888",
"port": 88888}

Program.cs

public class Program
{
    public static void Main(string[] args)
    {
     var config = ConfigurationHelper.GetConfiguration();
     var ip = config["Endpoint:ip"];
     var port = config["Endpoint:port"];
    }
 }
Eads answered 17/5, 2021 at 20:18 Comment(1)
Where does "ConfigurationHelper" come from? I see some examples of custom classes with this name but behind the scenes they do the same thing as the accepted answer.Impletion
P
-4

Use this code:

public class Program
{
    private static string _environmentName;

    public static void Main(string[] args)
    {
        var webHost = BuildWebHost(args);

        var config = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile($"appsettings.{_environmentName}.json", optional: true, reloadOnChange: true)
            .AddCommandLine(args)
            .Build();

        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureLogging((hostingContext, config) =>
    {
        config.ClearProviders();
        _environmentName = hostingContext.HostingEnvironment.EnvironmentName;
    }).UseStartup<Startup>().Build();
}
Portly answered 6/6, 2018 at 16:44 Comment(1)
I forgot to put the line BuildWebHost(args).Run(); in finish the method Main()Portly

© 2022 - 2024 — McMap. All rights reserved.