NET 核心控制台应用,如何配置每个环境的应用程序设置?

我有一个。NET Core 1.0.0控制台应用和双环境。我需要能够使用基于我在运行时设置的环境变量的 appSettings.dev.jsonappSettings.test.json。对于 ASP.NET 核心 web 应用程序来说,这似乎是非常直接的,通过依赖注入和 iHostingEnvironment 以及環境名称 env。变量,但是我应该如何连接控制台应用(除了编写使用 Microsoft.Framework.Configuration.EnvironmentVariables的自定义代码之外) ?

谢谢你。

115733 次浏览

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");
}
}

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
}
}

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();
}
}
}

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);
})

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.

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
}

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 :-)

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.

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)
{
// ...
}


// ...
}

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