172

ASP.NET Core support a new configuration system as seen here: https://docs.asp.net/en/latest/fundamentals/configuration.html

Is this model also supported in .NET Core console applications?

If not what is alternate to the previous app.config and ConfigurationManager model?

one noa
  • 345
  • 1
  • 3
  • 10
kimsagro
  • 15,513
  • 17
  • 54
  • 69

11 Answers11

295

For a .NET Core 2.0 console app, I did the following:

  1. Create a new file named appsettings.json at the root of the project (the file name can be anything)
  2. Add my specific settings to that file as json. For example:
{
  "myKey1" :  "my test value 1", 
  "myKey2" :  "my test value 2", 
  "foo" :  "bar" 
}
  1. Configure to copy the file to the output directory whenever the project is built (in VS -> Solution Explorer -> right-click file -> select 'Properties' -> Advanced -> Copy to Output Directory -> select 'Copy Always')

  2. Install the following nuget package in my project:

    • Microsoft.Extensions.Configuration.Json
  3. Add the following to Program.cs (or wherever Main() is located):

    static void Main(string[] args)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json");
    
        var configuration = builder.Build();
    
        // rest of code...
    }
    
  4. Then read the values using either of the following ways:

    string myKey1 = configuration["myKey1"];
    Console.WriteLine(myKey1);
    
    string foo = configuration.GetSection("foo").Value;
    Console.WriteLine(foo);
    

More info: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration?tabs=basicconfiguration#simple-configuration

Ray
  • 187,153
  • 97
  • 222
  • 204
  • I'm getting an issue related to `IConfigurationAssembly` being in an assembly that is not referenced - despite the Abstractions assembly being referenced. Ever see this? – BLAZORLOVER Nov 08 '17 at 17:09
  • I haven't. However, using `IConfigurationRoot` and not `IConfigurationAssembly`. – Ray Nov 08 '17 at 21:06
  • 1
    As I noticed Microsoft don't use IConfigurationRoot in their examples, but use IConfiguration. – aligin Dec 18 '17 at 10:56
  • IConfigurationRoot is not longer used in Core 2.0 – Calvin Feb 28 '18 at 20:18
  • 5
    [`IConfigurationRoot` is still available in .NET Core 2.0](https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.configuration.iconfigurationroot?view=aspnetcore-2.0#Applies_to). It inherits from `IConfiguration` but it's considered [a derived case of it that's not commonly used](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/#lf-content=225842398:758472358). Regardless, the code example has been updated to not include it and avoid any confusion. – Ray Mar 12 '18 at 22:15
  • 12
    2 notes: on point 4, you only need Microsoft.Extensions.Configuration.Json... It will include the other 2 by default. Second: If you want to load a section to an object, it is useful to know: var options = new FooOptions(); ConfigurationBinder.Bind(configuration.GetSection("foo"), options); You will need Microsoft.Extensions.Options.ConfigurationExtensions – Yepeekai Mar 13 '18 at 20:02
  • 1
    public class FooOptions{ public string myKey1 {get; set;} public string myKey2 {get;set;}} – Yepeekai Mar 13 '18 at 20:05
  • Only the package Microsoft.Extensions.Configuration.Json is required in the sample ;) – Fabito Aug 21 '18 at 12:10
  • 2
    Tools > NuGet Package Manager > Package Manager Console .. .. Install-Package Microsoft.Extensions.Configuration .. Install-Package Microsoft.Extensions.Configuration.FileExtensions .. Install-Package Microsoft.Extensions.Configuration.Json – Manohar Reddy Poreddy Sep 07 '18 at 07:02
  • appsettings.json din't work for me, so used app_settings.json – Manohar Reddy Poreddy Sep 07 '18 at 07:02
  • +1. Much better than the accepted answer, IMHO. There's a lot of unnecessary bloat in the accepted answer's code. – Steven Rands Dec 14 '18 at 09:33
  • @StevenRands I think the answer was accepted before most of the bloat was added, months after the original answer – Auspex Oct 21 '19 at 14:12
  • PERFECTION dude, nicely written! I followed each step and got configurations working 1st time! Thanks. – James Heffer Nov 05 '19 at 10:31
  • using vs 2017 enterprise. did a "using microsoft.extensions.configuration.json" and parts of the the builder syntax didn't look like they were being found by the compiler. My code still doesn't show SetBasePath and AddJsonFile as found in an include (normal text not colored). So if you think the routines aren't found, keep typing. Then when you're done see if it compiles. – renaissanceMan Jul 24 '20 at 18:44
  • Does this load user secrets and environment variables? – Juan De la Cruz Aug 09 '20 at 14:57
  • @JuanSalvadorPortugal you will need to update de appsettings.json file and rebuild ConfigurationBuilder by yourself – Murilo Maciel Curti Feb 13 '21 at 15:50
  • @Ray yours is the best answer. It continues to work very well on .net 5 – Murilo Maciel Curti Feb 13 '21 at 15:50
84

You can use this code snippet. It includes Configuration and DI.

public class Program
{
    public static ILoggerFactory LoggerFactory;
    public static IConfigurationRoot Configuration;

    public static void Main(string[] args)
    {
        Console.OutputEncoding = Encoding.UTF8;

        string environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

        if (String.IsNullOrWhiteSpace(environment))
            throw new ArgumentNullException("Environment not found in ASPNETCORE_ENVIRONMENT");

        Console.WriteLine("Environment: {0}", environment);

        var services = new ServiceCollection();

        // Set up configuration sources.
        var builder = new ConfigurationBuilder()
            .SetBasePath(Path.Combine(AppContext.BaseDirectory))
            .AddJsonFile("appsettings.json", optional: true);
        if (environment == "Development")
        {

            builder
                .AddJsonFile(
                    Path.Combine(AppContext.BaseDirectory, string.Format("..{0}..{0}..{0}", Path.DirectorySeparatorChar), $"appsettings.{environment}.json"),
                    optional: true
                );
        }
        else
        {
            builder
                .AddJsonFile($"appsettings.{environment}.json", optional: false);
        }

        Configuration = builder.Build();

        LoggerFactory = new LoggerFactory()
            .AddConsole(Configuration.GetSection("Logging"))
            .AddDebug();

        services
            .AddEntityFrameworkNpgsql()
            .AddDbContext<FmDataContext>(o => o.UseNpgsql(connectionString), ServiceLifetime.Transient);

        services.AddTransient<IPackageFileService, PackageFileServiceImpl>();

        var serviceProvider = services.BuildServiceProvider();

        var packageFileService = serviceProvider.GetRequiredService<IPackageFileService>();

        ............
    }
}

Oh, and don't forget to add in the project.json

{
  "version": "1.0.0-*",
  "buildOptions": {
    "emitEntryPoint": true,
    "copyToOutput": {
      "includeFiles": [
        "appsettings.json",
        "appsettings.Integration.json",
        "appsettings.Production.json",
        "appsettings.Staging.json"
      ]
    }
  },

  "publishOptions": {
    "copyToOutput": [
      "appsettings.json",
      "appsettings.Integration.json",
      "appsettings.Production.json",
      "appsettings.Staging.json"
    ]
  },
...
}
aligin
  • 1,370
  • 1
  • 13
  • 18
  • 13
    This answer is not ideal. Use `Directory.GetCurrentDirectory()` instead of `AppContext.BaseDirectory`. There should be no need for the hack afterwards. – Matyas Feb 09 '17 at 13:55
  • 2
    Or set the "Copy to Output Directory" property to "Copy if newer" in Visual Studio for the JSON files. – BuddhiP May 15 '18 at 06:09
  • For base dir to work in Web, Console and Winforms you can use this approach https://stackoverflow.com/a/33675039/1818723 – Pawel Cioch Nov 25 '18 at 03:06
  • Gary Woodfine described this in detail in a very good style on this post: https://garywoodfine.com/configuration-api-net-core-console-application/ – Javad Norouzi Apr 20 '19 at 09:53
  • @javad Only partly; I ended up here because I wanted the DI part, which he promised but I haven't found. He also didn't show how to use multiple config files as this example does. – Auspex Oct 21 '19 at 13:48
  • 5
    There doesn't appear to be a `SetBasePath` method unless you add `Microsoft.Extensions.Configuration.FileExtensions`. And no `AddJsonFile` without `Microsoft.Extensions.Configuration.Json` – Douglas Gaskell Nov 06 '19 at 22:17
  • 1
    `string environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");` this is soooo amateurish. You can screw other apps by setting global variable. You can't run dev and prod together. MS quality decreased so much with netcore – Toolkit Jan 15 '21 at 12:00
  • 1
    The microservices with its own environment in docker changes the approach the normal application must ne written. It's the reality. – aligin Jan 15 '21 at 19:26
  • This snippet helped me a lot, with very small tweaks. Thanks – Yogurtu Jun 29 '21 at 02:33
34

If you use Microsoft.Extensions.Hosting (version 2.1.0+) to host your console app and asp.net core app, all your configurations are injected with HostBuilder's ConfigureAppConfiguration and ConfigureHostConfiguration methods. Here's the demo about how to add the appsettings.json and environment variables:

    var hostBuilder = new HostBuilder()
        .ConfigureHostConfiguration(config =>
        {
            config.AddEnvironmentVariables();

            if (args != null)
            {
                // enviroment from command line
                // e.g.: dotnet run --environment "Staging"
                config.AddCommandLine(args);
            }
        })
        .ConfigureAppConfiguration((context, builder) =>
        {
            var env = context.HostingEnvironment;
            builder.SetBasePath(AppContext.BaseDirectory)
            .AddJsonFile("appsettings.json", optional: false)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            // Override config by env, using like Logging:Level or Logging__Level
            .AddEnvironmentVariables();

        })
        ... // add others, logging, services
        //;

In order to compile above code, you need to add these packages:

<PackageReference Include="Microsoft.Extensions.Configuration" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.1.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="2.1.0" />
Feiyu Zhou
  • 4,344
  • 32
  • 36
  • How is the environment determined? If I create a profile in launchSettings, it actually sets `ASPNETCORE_ENVIRONMENT` but then `context.HostingEnvironment.EnvironmentName` is not being set correctly – Sinaesthetic May 17 '18 at 19:15
  • You should use environment as the key, check this code: https://github.com/aspnet/Hosting/blob/dev/src/Microsoft.Extensions.Hosting.Abstractions/HostDefaults.cs – Feiyu Zhou May 18 '18 at 03:30
  • @FeiyuZhou that's a dead link – Auspex Oct 22 '19 at 09:05
  • 1
    Isn't _all_ of this solution after `new HostBuilder()` redundant? Doesn't `HostBuilder` do it all internally? – Auspex Oct 22 '19 at 09:07
  • 1
    @Auspex It depends on how you define your console app. If you need to define custom configurations then you should set like this. Here's the doc for dotnet core 3.0: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-3.0#host-configuration – Feiyu Zhou Oct 23 '19 at 08:11
  • Sure, if you want something custom, but you didn't _do_ anything custom, so the reader is going to think they have to do all that, when they likely don't. You might, for instance, have shown how to "use environment as the key", instead of posting a link, that is now dead, as a comment. – Auspex Oct 24 '19 at 09:16
  • My answer is for dotnet core 2.0, and it's enough for config with environment and appsettings.json which i use in my product code. The link I commented is for dotnet core 3.0, which is the latest config code. – Feiyu Zhou Oct 24 '19 at 13:31
  • Not your second link, the first one to GitHub. That's a 404. Anyway, I'm still sure dotnet 2.x did what your code does—I stripped that stuff out when I upgraded from 1.x – Auspex Oct 28 '19 at 10:48
11

On .Net Core 3.1 we just need to do these:

static void Main(string[] args)
{
  var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
}

Using SeriLog will look like:

using Microsoft.Extensions.Configuration;
using Serilog;
using System;


namespace yournamespace
{
    class Program
    {

        static void Main(string[] args)
        {
            var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
            Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(configuration).CreateLogger();

            try
            {
                Log.Information("Starting Program.");
            }
            catch (Exception ex)
            {
                Log.Fatal(ex, "Program terminated unexpectedly.");
                return;
            }
            finally
            {
                Log.CloseAndFlush();
            }
        }
    }
}

And the Serilog appsetings.json section for generating one file daily will look like:

  "Serilog": {
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
    "WriteTo": [
      {
        "Name": "File",
        "Args": {
          "path": "C:\\Logs\\Program.json",
          "rollingInterval": "Day",
          "formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact"
        }
      }
    ]
  }
Ernest
  • 2,039
  • 24
  • 19
  • 1
    after trying all those syntax from all over the web, yours is the one that worked for me, and it's so simple. – coder Jul 04 '20 at 20:42
10

I was mistaken. You can use the new ConfigurationBuilder from a netcore console application.

See https://docs.asp.net/en/latest/fundamentals/configuration.html for an example.

However, only aspnet core has dependency injection out of the box so you don't have the ability to have strongly typed configuration settings and automatically inject them using IOptions.

kimsagro
  • 15,513
  • 17
  • 54
  • 69
  • 10
    This answer is valid, but it should contain the necessary code, thus no upvote. – Matyas Feb 09 '17 at 13:54
  • 4
    All you need is to add package: `Microsoft.Extensions.Options` and call `service.AddOptions();` – Bruno Garcia Nov 06 '17 at 17:48
  • 3
    The entire (very long) linked page seems to be ASP.NET related, with mention of "WebHost" in every example. I got to this SO question after finding the linked page and thinking "ok, that's ASP.NET, what about Console Apps". – mackenir May 01 '19 at 14:21
  • That's a bit odd, @mackenir, because in 3.0 it's all been refactored so that it's all just Host! The only reference to WebHost itself is to point you to the 2.2 documentation. They could have been a little clearer that the `ConfigureWebHostDefaults()` calls in the examples are optional, and only for Web apps. – Auspex Oct 24 '19 at 09:23
10

If you use .netcore 3.1 the simplest way use new configuration system to call CreateDefaultBuilder method of static class Host and configure application

public class Program
{
    public static void Main(string[] args)
    {
        Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((context, config) =>
            {
                IHostEnvironment env = context.HostingEnvironment;
                config.AddEnvironmentVariables()
                    // copy configuration files to output directory
                    .AddJsonFile("appsettings.json")
                    // default prefix for environment variables is DOTNET_
                    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                    .AddCommandLine(args);
            })
            .ConfigureServices(services =>
            {
                services.AddSingleton<IHostedService, MySimpleService>();
            })
            .Build()
            .Run();
    }
}

class MySimpleService : IHostedService
{
    public Task StartAsync(CancellationToken cancellationToken)
    {
        Console.WriteLine("StartAsync");
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        Console.WriteLine("StopAsync");
        return Task.CompletedTask;
    }
}

You need set Copy to Output Directory = 'Copy if newer' for the files appsettings.json and appsettings.{environment}.json Also you can set environment variable {prefix}ENVIRONMENT (default prefix is DOTNET) to allow choose specific configuration parameters.

.csproj file:

<PropertyGroup>
  <OutputType>Exe</OutputType>
  <TargetFramework>netcoreapp3.1</TargetFramework>
  <RootNamespace>ConsoleApplication3</RootNamespace>
  <AssemblyName>ConsoleApplication3</AssemblyName>
</PropertyGroup>

<ItemGroup>
  <PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.7" />
  <PackageReference Include="Microsoft.Extensions.Hosting" Version="3.1.7" />
</ItemGroup>

<ItemGroup>
  <None Update="appsettings.Development.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
  <None Update="appsettings.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>

more details .NET Generic Host

Dmitry Kolchev
  • 2,116
  • 14
  • 16
  • oh finally thank you for pointing me to the right direction! It is so important to distinguish ASP.NET.CORE and DOTNET.CORE If using a .NET Core application (not asp web stuff, but console or windows/linux services for microservices) you have to set the debugging environment variables to *DOTNET_ENVIRONMENT*. Then it will work with context.HostingEnviornment.EnviornmentName. – rogaa Oct 05 '20 at 12:47
4

It's something like this, for a dotnet 2.x core console application:

        using Microsoft.Extensions.Configuration;
        using Microsoft.Extensions.DependencyInjection;
        using Microsoft.Extensions.Logging;

        [...]
        var configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddEnvironmentVariables()
            .Build();
        var serviceProvider = new ServiceCollection()
            .AddLogging(options => options.AddConfiguration(configuration).AddConsole())
            .AddSingleton<IConfiguration>(configuration)
            .AddSingleton<SomeService>()
            .BuildServiceProvider();
        [...]
        await serviceProvider.GetService<SomeService>().Start();

The you could inject ILoggerFactory, IConfiguration in the SomeService.

lnaie
  • 1,011
  • 13
  • 16
3

Install these packages:

  • Microsoft.Extensions.Configuration
  • Microsoft.Extensions.Configuration.Binder
  • Microsoft.Extensions.Configuration.EnvironmentVariables
  • Microsoft.Extensions.Configuration.FileExtensions
  • Microsoft.Extensions.Configuration.Json

Code:

static void Main(string[] args)
    {
        var environmentName = Environment.GetEnvironmentVariable("ENVIRONMENT");
        Console.WriteLine("ENVIRONMENT: " + environmentName);

        var builder = new ConfigurationBuilder()
           .SetBasePath(Directory.GetCurrentDirectory())
           .AddJsonFile("appsettings.json", false)
           .AddJsonFile($"appsettings.{environmentName}.json", true)
           .AddEnvironmentVariables();

        IConfigurationRoot configuration = builder.Build();
        var mySettingsConfig = configuration.Get<MySettingsConfig>();

        Console.WriteLine("URL: " + mySettingsConfig.Url);
        Console.WriteLine("NAME: " + mySettingsConfig.Name);

        Console.ReadKey();
    }

MySettingsConfig Class:

public class MySettingsConfig
{
    public string Url { get; set; }
    public string Name { get; set; }
}

Your appsettings can be as simple as this: enter image description here

Also, set the appsettings files to Content / Copy if newer: content

alansiqueira27
  • 8,129
  • 15
  • 67
  • 111
2

Other solutions work but not in case that you want inject IConfigurationRoot in other services. I simply did it this way:

Install Microsoft.Extensions.Configuration.Json then

static void Main(string[] args)
{
    var serviceProvider = new ServiceCollection()
        .AddSingleton(_ =>
            new ConfigurationBuilder()
                .SetBasePath(Path.Combine(AppContext.BaseDirectory))
                .AddJsonFile("appsettings.json", optional: true)
                .Build())
        .BuildServiceProvider();

     // Rest of code ...
}

and in other services inject it or use

serviceProvider.GetService<IConfigurationRoot>()
Arman Ebrahimpour
  • 4,252
  • 1
  • 14
  • 46
1

You can use LiteWare.Configuration library for that. It is very similar to .NET Framework original ConfigurationManager and works for .NET Core/Standard. Code-wise, you'll end up with something like:

string cacheDirectory = ConfigurationManager.AppSettings.GetValue<string>("CacheDirectory");
ulong cacheFileSize = ConfigurationManager.AppSettings.GetValue<ulong>("CacheFileSize");

Disclaimer: I am the author of LiteWare.Configuration.

1

Just piling on... similar to Feiyu Zhou's post. Here I'm adding the machine name.

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
          .ConfigureAppConfiguration((context, builder) =>
          {
            var env = context.HostingEnvironment;
            var hostname = Environment.MachineName;
            builder.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
              .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
              .AddJsonFile($"appsettings.{hostname}.json", optional: true, reloadOnChange: true);
            builder.AddEnvironmentVariables();
            if (args != null)
            {
              builder.AddCommandLine(args);
            }
          })
        .UseStartup<Startup>();
  }
bvj
  • 3,294
  • 31
  • 30