支持多环境的Asp.Net Core,不够用还可以添加子环境

632 阅读3分钟

ASP.NET Core开箱即用,具有“多环境”的概念,该概念使您的应用可以根据运行的环境使用不同的设置。例如,您可以拥有开发/测试/生产环境,每个环境都有自己的环境设置文件,以及所有环境共享的通用设置文件,还能再多吗?

1.多环境支持

  • appsettings.json: 全局设置
  • appsettings.Development.json:特定于开发环境的设置
  • appsettings.Staging.json:特定于测试环境的设置
  • appsettings.Production.json:特定于生产环境的设置

使用默认配置,特定于环境的设置将覆盖全局设置,因此,如果已经在全局设置文件中指定了不变的设置,则不必在每个环境中都指定不变的设置

当然,您可以使用自己喜欢的任何名称的环境。开发/测试/生产只是一个惯例。

您可以通过ASPNETCORE_ENVIRONMENT环境变量或--environment命令行开关指定要使用的环境。在Visual Studio中工作时,通常在启动配置文件中执行此操作Properties/launchSettings.json

2、局限

此功能非常方便,但有时还不够。即使在给定的环境中,您可能也需要不同的设置来测试不同的方案。

作为一个具体的例子,我开发了一个解决方案,其中包括一个Web API和一个身份验证服务器。该API使用身份验证服务器提供的JWT承载令牌对用户进行身份验证。大多数时候,当我使用API​​时,不需要对身份验证服务器进行更改,并且我非常高兴使用在阿里云开发环境中部署的身份验证服务器。但是,当我确实需要对身份验证服务器进行更改时,我必须修改API设置,以便它改用本地身份验证服务器。而且我必须小心,不要提交更改,以免破坏阿里云中的开发实例。这是一个小问题,但很烦人……

一种可能的解决方案是使用其自己的设置文件创建一个新的“ DevelopmentWithLocalAuth”环境。但是设置将与开发环境中的设置相同,唯一的更改是身份验证服务器URL。我讨厌同一件事有多个副本,因为要使它们保持同步是很痛苦的。我真正想要的是一种使用开发环境设置的方法,而无需修改开发环境设置即可覆盖我的需求。

3、引入“ 子环境”

这不是一个实际的功能,只是我起的一个名字。但要点是,您可以轻松引入另一个“级别”的配置设置,仅覆盖“父”环境的某些设置。

例如,在我的场景中,我想引入一个appsettings.Development.LocalAuth.json文件,该文件继承开发环境的设置,并且仅覆盖身份验证服务器的URL:

{
    "Authentication": {
        "Authority": "https://localhost:6001"
    }

这样做的方法是在构建主机时,将新文件添加为配置源Program.cs:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((context, builder) =>
        {
            string subenv = context.Configuration["SubEnvironment"];
            if (!string.IsNullOrEmpty(subenv))
            {
                var env = context.HostingEnvironment;
                builder.AddJsonFile($"appsettings.{env.EnvironmentName}.{subenv}.json", optional: true, reloadOnChange: true);
            }
        })
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

备注:此代码适用于ASP.NET Core 3.0 +,但是如果您使用ASP.NET Core 2.0 的WebHostBuilder代替,则同样适用HostBuilder。

魔术发生在调用ConfigureAppConfiguration时。它添加了一个新的JSON文件,其名称取决于环境和子环境。由于此配置源是在现有配置源之后添加的,因此它将覆盖以前的源提供的设置。

子环境的名称是从主机配置中检索的,主机配置本身是基于以ASPNETCORE_和命令行参数开头的环境变量。因此,要指定您想要“ LocalAuth”子环境,您需要将ASPNETCORE_SUBENVIRONMENT环境变量设置为“ LocalAuth”。

就是这样!您可以针对特定方案优化现有环境了。

4、再次升级

由于新的配置源是最后添加的,因此它将覆盖所有以前的配置源,而不仅仅是默认appsettings.json文件。

默认的主机构建器在JSON文件之后添加用户机密,环境变量和命令行参数,因此子环境设置也将覆盖这些内容。

这不是很理想的,但对于大多数情况而言可能不是主要问题。但我们需要解决它,怎么办?

解决方法是将子环境配置源插入到现有JSON源之后,但在用户密钥源之前。它使代码更加复杂,但是可行:

...
        .ConfigureAppConfiguration((context, builder) =>
        {
            string subenv = context.Configuration["SubEnvironment"];
            if (!string.IsNullOrEmpty(subenv))
            {
                var env = context.HostingEnvironment;
                var newSource = new JsonConfigurationSource
                {
                    Path = $"appsettings.{env.EnvironmentName}.{subenv}.json",
                    Optional = true,
                    ReloadOnChange = true
                };
                newSource.ResolveFileProvider();

                var lastJsonConfigSource = builder.Sources
                    .OfType<JsonConfigurationSource>()
                    .LastOrDefault(s => !s.Path.Contains("secrets.json"));
                if (lastJsonConfigSource != null)
                {
                    var index = builder.Sources.IndexOf(lastJsonConfigSource);
                    builder.Sources.Insert(index + 1, newSource);
                }
                else
                {
                    builder.Sources.Insert(0, newSource);
                }
            }
        })
        ...

5、小结

关注楼主,不迷路!