在 appSettings.json 文件中展开环境变量

Expand environment variables in appSettings.json file

有没有办法 "out of the box" 让 appsettings.json 值中的环境变量自动扩展?

举个人为的例子:

{
  ...
  "MyPath1": "C:/MyApp/%ENV%/Myfolder1/MyFile1.dat",
  "MyConnectionString":  "Server=MyServer%ENV%..."
  ...
}

我的 objective 是能够通过更改单个环境变量来切换我的环境,并让它影响多个应用程序设置值,而不是拥有每个环境的配置文件。

更新

我查看了 the source code of JsonConfigurationProvider,据我所知,没有这样的功能。

我可以看到,通过从 JsonConfigurationProvider 派生自定义 class 并覆盖 Load() 方法应该是可能的:

public override void Load()
{
    base.Load();
    foreach(var key in Data.Keys)
    {
        Data[key] = Environment.ExpandEnvironmentVariables(key);
    }
}

但我对 .NET Core 配置还很陌生,这引出了第二个问题:

如何使用此自定义实现来替换标准实现? IE。删除默认的 appsettings.json 和 appsettings.environment.json 提供程序并替换为自定义提供程序。大概是要在Program.cs:

中添加一些东西
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureAppConfiguration(config =>
        {
            config.??? what do I need here?
        }
        );

要创建和使用自定义配置源,需要两个实现:

  1. IConfigurationSource
  2. IConfigurationProvider

IConfigurationSource 实现被添加到 IConfigurationBuilder 的源代码中。此实现还负责创建自己的 IConfigurationProvider,它负责从源加载数据。

这里是 IConfigurationSource (ExpandJsonConfigurationSource) 和 IConfigurationProvider (ExpandJsonConfigurationProvider) 的自定义实现:

public class ExpandJsonConfigurationSource : JsonConfigurationSource
{
    public override IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        EnsureDefaults(builder);
        return new ExpandJsonConfigurationProvider(this);
    }
}

public class ExpandJsonConfigurationProvider : JsonConfigurationProvider
{
    public ExpandJsonConfigurationProvider(ExpandJsonConfigurationSource source)
        : base(source) { }

    public override void Load()
    {
        base.Load();
        Data = Data.ToDictionary(
            x => x.Key,
            x => Environment.ExpandEnvironmentVariables(x.Value),
            StringComparer.OrdinalIgnoreCase);
    }
}

这里没有发生太多事情。这些实现只是遵循与现有 JsonConfigurationSourceJsonConfigurationProvider 实现相同的方法,具有用于扩展环境变量的自定义处理。

要替换基于 JSON 的预配置源,请使用以下内容:

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureAppConfiguration((ctx, builder) =>
        {
            var jsonConfigurationSources = builder.Sources
                .OfType<JsonConfigurationSource>()
                .ToList();

            foreach (var jsonConfigurationSource in jsonConfigurationSources)
            {
                var indexOfJsonConfigurationSource = builder.Sources
                    .IndexOf(jsonConfigurationSource);

                builder.Sources.RemoveAt(indexOfJsonConfigurationSource);
                builder.Sources.Insert(
                    indexOfJsonConfigurationSource,
                    new ExpandJsonConfigurationSource
                    {
                        FileProvider = jsonConfigurationSource.FileProvider,
                        Path = jsonConfigurationSource.Path,
                        Optional = jsonConfigurationSource.Optional,
                        ReloadOnChange = jsonConfigurationSource.ReloadOnChange
                    });
            }
        });

传递给 ConfigureAppConfiguration 的委托执行以下操作:

  1. 找到 JsonConfigurationSource 的所有已配置实例。应该有两个实例:appsettings.json 和例如appsettings.Development.json.

  2. 对于每个实例:

  3. 确定实例在预配置源中的位置。

  4. 删除实例。

  5. ExpandJsonConfigurationSource 的实例替换删除的实例,复制属性以确保它具有相同的路径、可选标志等

我创建了一个库来执行变量替换,它替换 任何 配置源,而不仅仅是环境变量。 参见:https://github.com/molinch/ConfigurationSubstitutor

您只需将其注册为另一个配置源,这通过在 ConfigurationBuilder 上调用 .EnableSubstitutions() 来完成。

以你为例:

  • 如果在 appsettings.json 你有:"MyPath": "C:/MyApp/%ENV%/Myfolder1/MyFile1.dat"
  • 并且您有以下环境变量:ENV = Foo
  • 那么你应该启用替换:
.EnableSubstitutions("%", "%")

最后,当从配置中请求 MyPath 时,您将获得:C:/MyApp/Foo/Myfolder1/MyFile1.dat