103

I have a .NET Core 1.0.0 console application and two environments. I need to be able to use appSettings.dev.json and appSettings.test.json based on environment variables I set at run time. This seems to be quite straight forward for ASP.NET Core web applications, via dependency injection and IHostingEnvironment and the EnvironmentName env. variable, however how should I wire things up for the console application (besides writing my own custom code that uses Microsoft.Framework.Configuration.EnvironmentVariables)?

Thank you.

user2916547
  • 1,963
  • 5
  • 17
  • 21

12 Answers12

132

This is how we do it in our .netcore console app. The key here is to include the right dependencies on your project namely (may be not all, check based on your needs) and copy to output the appSetting.json as part of your buildoptions

  {
    "buildOptions": {
    "emitEntryPoint": true,
    "copyToOutput": {
       "include": [
       "appsettings*.json",
       "App*.config"
                 ]
          }
},
using Microsoft.Extensions.Configuration;
namespace MyApp
{
    public static void Main(string[] args)
    {
        var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
       

        var builder = new ConfigurationBuilder()
            .AddJsonFile($"appsettings.json", true, true)
            .AddJsonFile($"appsettings.{environmentName}.json", true, true)
            .AddEnvironmentVariables();
        var configuration = builder.Build();
        var myConnString= configuration.GetConnectionString("SQLConn");
    }
}
Pang
  • 9,564
  • 146
  • 81
  • 122
Jaya
  • 3,721
  • 4
  • 32
  • 48
  • 7
    Thank you. I have eventually ended up using a more convoluted version of that, using `new ConfigurationBuilder().AddEnvironmentVariables()` and finding `ASPNETCORE_ENVIRONMENT`. – user2916547 Nov 21 '16 at 14:10
  • I don't seem to find a buildoptions in the console app. – liang Oct 24 '17 at 18:35
  • 3
    I think you should add a nuget `Microsoft.Extensions.Configuration.Json` nuget package: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.0&tabs=basicconfiguration#json-configuration – Junior Mayhé May 16 '18 at 13:58
  • shouldn't `Configuration = builder.Build();` be `IConfigurationRoot Configuration = builder.Build();`? – Elfalem Jan 05 '19 at 05:23
  • 3
    how will this Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") work without reference to Microsoft.AspNetCore.Hosting ? – HaBo Mar 15 '19 at 09:56
  • @HaBo It won't, you'll need to run something like `Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Test");` or set the environment variable in your environment. See https://learn.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-2.2 – Eric Herlitz Apr 15 '19 at 13:16
  • 5
    With the new csproj structure you would PreserveNewest – Thulani Chivandikwa May 02 '19 at 21:38
  • 2
    Please update your answer. Apparently there is no need in json part of your code example... – Akmal Salikhov Nov 29 '19 at 07:57
  • Also need to ensure that all versions of appsettings.json (e.g. appsettings.Development.json) are set to 'copy if newer' so that they go to output directory as well. – douglas.kirschman Dec 07 '20 at 18:41
  • I can't believe this is the accepted solution. What if I have both dev and prod running on the same machine? What if I forget that some app is running and change ASPNETCORE_ENVIRONMENT? This is soooo amateurish and so much inferior to classic .NET – Toolkit Jan 14 '21 at 13:18
  • 1
    @Toolkit TBH, I'm still trying to understand why you would use `var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");` in the first place. If you have to do something like `Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Test");` then why not just set `var environmentName = "Test";` and be done with the hack? – Arvo Bowen Jan 19 '21 at 22:52
  • 1
    @ArvoBowen They are only reading the environment variable ASPNETCORE_ENVIRONMENT in code not setting it. If you put the code "var environmentName = "Test";" in your program how would you run it in production? – Paul May 28 '21 at 14:45
  • Add nuget Microsoft.Extensions.Configuration.EnvironmentVariables – andrew.fox Mar 23 '23 at 10:47
30

As of Net Core 3.1++, the generic Host class Microsoft.Extensions.Hosting.Host uses DOTNET_ENVIRONMENT environment variable instead of ASPNETCORE_ENVIRONMENT.

Setting DOTNET_ENVIRONMENT="Development" in Project Debug settings will work without any additional coding.

Or you can add your own prefix like this:

// works for WPF but should work similar for Console Apps
public partial class App : Application
{
    private readonly IHost _host;

    public App()
    {
        _host = Host.CreateDefaultBuilder()
            .ConfigureHostConfiguration(configHost => {
                configHost.AddEnvironmentVariables(prefix: "PREFIX_");
            })
            .ConfigureServices((context, services) =>
            {
                ConfigureServices(context.Configuration, services);
            })
            .Build();
    }

    private void ConfigureServices(
        IConfiguration configuration,
        IServiceCollection services)
    {
       // ...
    }

    // ...
}
Merilix2
  • 476
  • 4
  • 5
29

For those who are using .NET Core version 2.1.0+ and Microsoft.Extensions.Hosting to host your console app, you can use the following code (according to the Feiyu Zhou's answer in another thread):

var hostBuilder = new HostBuilder()
    .ConfigureHostConfiguration(config =>
    {
        if (args != null)
        {
            // enviroment from command line
            // e.g.: dotnet run --environment "Staging"
            config.AddCommandLine(args);
        }
    })
    .ConfigureAppConfiguration((context, builder) =>
    {
        builder.SetBasePath(AppContext.BaseDirectory)
            .AddJsonFile("appsettings.json", optional: false)
            .AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", optional: true);
    })
victorm1710
  • 1,263
  • 14
  • 11
10

There are two IHostingEnvironment interfaces that you should use. One is for ASP.NET Core Applications, the other one is for .NET Core Console applications. You can use this code example for both:

using System;
using System.IO;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting.Internal;

namespace MyApplication.Common
{
    public static class ConfigurationFactory
    {
        /// <summary>
        /// Use for ASP.NET Core Web applications.
        /// </summary>
        /// <param name="config"></param>
        /// <param name="env"></param>
        /// <returns></returns>
        public static IConfigurationBuilder Configure(IConfigurationBuilder config, IHostingEnvironment env)
        {
            return Configure(config, env.EnvironmentName);
        }

        /// <summary>
        /// Use for .NET Core Console applications.
        /// </summary>
        /// <param name="config"></param>
        /// <param name="env"></param>
        /// <returns></returns>
        private static IConfigurationBuilder Configure(IConfigurationBuilder config, Microsoft.Extensions.Hosting.IHostingEnvironment env)
        {
            return Configure(config, env.EnvironmentName);
        }

        private static IConfigurationBuilder Configure(IConfigurationBuilder config, string environmentName)
        {
            return config
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{environmentName}.json", optional: true, reloadOnChange: true)
                .AddEnvironmentVariables();
        }

        /// <summary>
        /// Use for .NET Core Console applications.
        /// </summary>
        /// <returns></returns>
        public static IConfiguration CreateConfiguration()
        {
            var env = new HostingEnvironment
            {
                EnvironmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production",
                ApplicationName = AppDomain.CurrentDomain.FriendlyName,
                ContentRootPath = AppDomain.CurrentDomain.BaseDirectory,
                ContentRootFileProvider = new PhysicalFileProvider(AppDomain.CurrentDomain.BaseDirectory)
            };

            var config = new ConfigurationBuilder();
            var configured = Configure(config, env);
            return configured.Build();
        }
    }
}
MovGP0
  • 7,267
  • 3
  • 49
  • 42
  • 1
    Console App "version" namespace "Microsoft.Extensions.Hosting" , interface "IHostingEnvironment" , assembly file : "microsoft.extensions.hosting.abstractions\2.1.1\lib\netstandard2.0\Microsoft.Extensions.Hosting.Abstractions.dll" – granadaCoder Dec 03 '18 at 19:29
  • 1
    Here is the list of nuget packages I had to add to get this code to work. – granadaCoder Dec 03 '18 at 22:30
  • Should I create a dependency of Microsoft.AspNetCore namespace in a console app project? – Rafael Nov 12 '19 at 12:55
  • So I just updated my code for 3.1. Next comments are the csproj. The "abstractions" 2.1.1 does not exist in 3.1. You have to use a "FrameworkReference". Note, it'll take 2 extra comments to give the germane csproj code. – granadaCoder Jan 09 '20 at 15:04
  • 1
    netcoreapp3.1 – granadaCoder Jan 09 '20 at 15:05
  • 1
  • 2
    This answer should be updated as it currently uses depreciated code. You should remove the `using Microsoft.AspNetCore.Hosting;` statement and clearly define the new suggested interfaces typed out completely in this case. "Use for ASP.NET Core Web applications.": `public static IConfigurationBuilder Configure(IConfigurationBuilder config, Microsoft.AspNetCore.Hosting.IWebHostEnvironment env)` and "Use for .NET Core Console applications.": `private static IConfigurationBuilder Configure(IConfigurationBuilder config, Microsoft.Extensions.Hosting.IHostEnvironment env)`. – Arvo Bowen Jan 19 '21 at 23:15
  • I don't understand why all this needs to be done though. When I'm running my console app in the IDE "EnvironmentName" always comes back as `NULL`. Then I end up with it adding the JSON file `appsettings..json` to the mix. Should this be giving me an "EnvironmentName" of something like "Debug"? I'm calling `IConfiguration _config = ConfigurationFactory.CreateConfiguration();` from my console's Main() method. Should I be using it differently? – Arvo Bowen Jan 19 '21 at 23:46
9

If like me, you're simply trying to have a different configuration file for Release and Development mode, just add a appsettings.Development.json file with CopyToOutputDirectory setting set to true in the file's property window.

Now, to access the file depending on the build configuration, you can use the #if DEBUG preprocessor directive.

Here's an example :

static void Main(string[] args)
{

#if DEBUG
    var builder = new ConfigurationBuilder()
            .AddJsonFile($"appsettings.Development.json", true, true);
#else
    var builder = new ConfigurationBuilder()
            .AddJsonFile($"appsettings.json", true, true);
#endif

    var configuration = builder.Build();

    // ... use configuration
}
chaosifier
  • 2,666
  • 25
  • 39
  • 4
    This is a poor solution as it can hide compilation errors, which then become apparent once you push to a build server and the directive becomes true/false. It's much better to use an environment variable. I'm not judging though - I have done this in the past many times, it's just that I've run into the issue I mentioned a few times. – jcvandan Dec 03 '19 at 12:31
  • 2
    I'd recommend that you *always* add the `appsettings.json` file (which addresses @jcvandan's issue of never loading it) and `#if DEBUG` *also* load the `appsettings.Development.json` - the standard way is to allow the Development to override settings if required, not having to specify them all. – oatsoda Jun 27 '20 at 15:23
  • 1
    `#if DEBUG` is what I use, but only to set the environment variable to `Development` or otherwise `Production` by default. I have found for console apps, `Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")` always returns `Production` unless you use a launchSettings.json file (or other more buried tweak) which none of these solutions mention. With the default VS template and default console app template, this is the only solution that works to simply have a Development environment with no extra configs. – Sum None Jan 22 '23 at 03:46
3

These environment things seems to work for most ppl, but I don't aggree at all with all that environmental management. Whether the runtime nor the target system knows what it is. Only you, as a developer or a deployment mechanism, knows what the target system is.

Everyone is talking about ASPNETCORE_ENVIRONMENT variable, even official documentation like here https://learn.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-3.0. But in fact someone has to define a system explicitly as production system for example, by setting ASPNETCORE_ENVIRONMENT manually once. Do you really want to assume and rely on it that this is already set in every environment you use? No, you can't. What if you have to deploy a console app to a batch server where no website is running? ASPNETCORE_ENVIRONMENT is not available. What if you need to deploy and run a .net core webapi without IIS, only with kestrel? No web.config and no environment variable. Do you want your admins/operation team to set this misleading variable for your console app? In this context i've seen lots of projects which have appsettings like this per project:

appsettings.json
appsettings.development.json
appsettings.test.json
appsettings.uat.json
appsettings.staging.json
appsettings.production.json

Keep in mind that by default each of these files will be published and also be deployed to the target system. At a first look it looks very easy to let the environment "decide" which config should be used. But you have configuration and also potentially credentials deployed on a system which is not intended for it.

Conclusion

I recommend appsettings.json + appsettings.release.json. First one is only for dev. Change it, play with it like you want. Last one is a VALID config ready for deployment (process). Before deployment starts, transform the config to be ready for the target system. That's it. No need to rely on settings on the target machine, no messy configs. Keep full control of your app even when servers change quickly (like scaling in general, VMs, cloud, whatever)

I appreciate constructive feedback :-)

  • 1
    You're missing the point somewhat and yes, the condition could be determined by a configuration value instead of an environment variable. I have different app behavior in Web API's where I use swagger for developers to examine and test endpoints. Having a consistent release management process of promoting the same binaries through to a Production environment, this feature needs to be toggled. Whether that is achieved by config setting per app/environment or a single environment variable is irrelevant except environment settings apply to all apps on the same server, unlike app configs. – Antony Booth Jan 15 '20 at 19:38
  • No one has to define a system as production system explicitly because this is the default. But you as a developer define YOUR own system as development environment and override default production settings with those in your *.development.json files. – Merilix2 Jul 05 '22 at 17:02
2

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
2

For anyone on .NetCore 3.1 and using the .CreateDefaultBuilder(args) extension. Just add -environment "Development" to your command line arguments in the Debug settings. Done.

Adam Hardy
  • 377
  • 3
  • 9
1

Per the docs, this is all provided automatically by the default host builder. The only code required to include the correct appsettings file based on environment, command-line arguments, environment variables, user secrets (for Development environment only), etc is to use the default builder:

IHost host = Host.CreateDefaultBuilder(args)
    .ConfigureServices((hostContext, services) =>
    {
        // configure services here
    })
    .Build();

host.Run();

The key is to use the CreateDefaultBuilder() method which pre-configures all of these sources. You can also layer additional sources such as in-memory collection using the fluent api which will take precedence over the formerly mentioned sources.

Sources:

.NET Generic Host

Host.CreateDefaultBuilder() Method

user700390
  • 2,287
  • 1
  • 19
  • 26
0

You can do this for ASP.Net Core environment variable (ASPNETCORE_ENVIRONMENT): -

using Microsoft.AspNetCore.Hosting;
using System;

public class Program {
    private static string HostingEnvironment => Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
    private static bool IsEnvironment(string environmentName) => HostingEnvironment?.ToLower() == environmentName?.ToLower() && null != environmentName;

    private static bool Development => IsEnvironment(EnvironmentName.Development);
    private static bool Production => IsEnvironment(EnvironmentName.Production);
    private static bool Staging => IsEnvironment(EnvironmentName.Staging);

    public static void Main(string[] args) { // Your code here }
}

Then you can simply use the property

    public static void Main(string[] args) {
        if (Development){
            // Blow up the planet
        }
    }
Antony Booth
  • 413
  • 4
  • 5
  • 8
    The question was not about asp.net core. – Miklós Tóth Feb 06 '18 at 18:48
  • 1
    I know, but the *only* things about this that are remotely asp.net core related are the name of the environment variable and the .net core library used to get the string constants for 'Development', 'Staging' & 'Production'. I thought it would be useful to use a legitimate environment variable instead of one I made up. It could be anything and not be in an asp.net core application at all. – Antony Booth Feb 07 '18 at 19:22
  • 1
    Is this one (and its siblings) more "NON asp.net (core)" 'ish ? https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.hosting.environmentname.development – granadaCoder Dec 04 '18 at 13:22
0

hai i used like this to get BaseURL of api to call from console app cnfiguring .json file

 public  class Helper
    {
        public static string GetConfigurationItems()
        {
            string? url;
            ConfigurationItems cf = new ConfigurationItems();

            var builder = new ConfigurationBuilder()
                               .AddJsonFile("appsettings.json", optional: true);
            IConfigurationRoot configuration = builder.Build();
            configuration.GetSection("ConfigurationItem").Bind(cf);
            url= cf.BaseURL;
            return url;
        }
       
    }

this is appsetting.json file

    {
  "ConfigurationItem": {
      "BaseURL": "https://localhost:46356"
    }
  }

this is concating baseUrl and route of api

            string apiURL = Helper.GetConfigurationItems() + 
"api/Employee/getAllEmployees";

and change setting of appsetting.json file in properties: copy to output directory = copy alway

Harsha
  • 1
  • 2
0

I tried the answer shared by @Merilix2 but that didn't help me.

For .NET Core 7, the following worked for me in the Console application.

  1. Right-click on Project and select the last option Properties.
  2. Go to Debug and then select General.
  3. Click on link Open debug launch profiles UI
  4. In the opened window search for the Environment variables option. Set Name and Value where Name is the key.

The below screenshot can help much better way.

How to use appsettings as per environment in Console app

You must set the Copy to Output Directory as Copy always for appsettings.Develoment.json or one as per your environment.

Properties window for appsettings.Development.json file

I missed sharing that I have ConfigurationBuilder set like this.

private static ConfigurationBuilder GetConfigBuilder()
{
    var builder = new ConfigurationBuilder();

    builder.SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
        .AddEnvironmentVariables();

    return builder;
}
Vikram Singh Saini
  • 1,749
  • 3
  • 22
  • 42