翻译自 https://docs.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-6.0
ASP.NET Core 基于运行环境使用一个环境变量配置应用程序的行为。
ASP.NET Core 从下列环境变量读取配置决定运行时的环境:
IHostEnvironment.EnvironmentName 可以被设置为任意值,但是下面的值是由框架本身提供的:
下面的代码:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } if (env.IsProduction() || env.IsStaging() || env.IsEnvironment("Staging_2")) { app.UseExceptionHandler("/Error"); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); }); }
Environment Tag Helper 使用 IHostEnvironment.EnvironmentName 的值包含或者排除元素中的标记:
<environment include="Development"> <div>The effective tag is: <environment include="Development"></div> </environment> <environment exclude="Development"> <div>The effective tag is: <environment exclude="Development"></div> </environment> <environment include="Staging,Development,Staging_2"> <div> The effective tag is: <environment include="Staging,Development,Staging_2"> </div> </environment>示例代码(sample code)中的 About page 页面包含了上面的标记并且显示了 IWebHostEnvironment.EnvironmentName 的值。
在 Windows 和 macOS上,环境变量和值是不区分大小写的,在 Linux 上是区分大小写的。
本文档中使用的示例代码(sample code)是基于名称为 EnvironmentsSample 的 Razor Pages 工程。
下面的代码创建并运行名称为 EnvironmentsSample 的 web 应用程序:
dotnet new webapp -o EnvironmentsSample cd EnvironmentsSample dotnet run --verbosity normal
当应用程序运行的时候,会有以下输出:
Using launch settings from c:\tmp\EnvironmentsSample\Properties\launchSettings.json info: Microsoft.Hosting.Lifetime[0] Now listening on: https://localhost:5001 info: Microsoft.Hosting.Lifetime[0] Application started. Press Ctrl+C to shut down. info: Microsoft.Hosting.Lifetime[0] Hosting environment: Development info: Microsoft.Hosting.Lifetime[0] Content root path: c:\tmp\EnvironmentsSample
开发环境可以启用一些不应该在生产环境中暴露的功能特性。例如, ASP.NET Core 的模板在开发环境中启用了 Developer Exception Page。
本机开发环境可以在工程中的 Properties\launchSettings.json 中设置。在 launchSettings.json 中设置的环境值会覆盖系统中的环境变量值。
launchSettings.json 文件:
下面的 JSON 展示了一个使用 Visual Studio 或者 dotnet new 创建的名称为 EnvironmentsSample ASP.NET Core web 工程的 launchSettings.json 文件的内容:
{ "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:64645", "sslPort": 44366 } }, "profiles": { "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "EnvironmentsSample": { "commandName": "Project", "launchBrowser": true, "applicationUrl": "https://localhost:5001;http://localhost:5000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } }
上面的标记包含了两个配置文件:
commandName 的值指定了要加载的 web 服务器。commandName 的值可以是以下值的其中之一:
Visual Studio 项目属性的 Debug 标签提供了编辑 launchSettings.json 文件的。对项目配置文件的修改可能直到 web 服务器重启后才会生效。Kestrel 在它可能检测到它的环境的之前必须重新启动。
下面的 launchSettings.json 文件包含多个配置:
{ "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:64645", "sslPort": 44366 } }, "profiles": { "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "IISX-Production": { "commandName": "IISExpress", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Production" } }, "IISX-Staging": { "commandName": "IISExpress", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Staging", "ASPNETCORE_DETAILEDERRORS": "1", "ASPNETCORE_SHUTDOWNTIMEOUTSECONDS": "3" } }, "EnvironmentsSample": { "commandName": "Project", "launchBrowser": true, "applicationUrl": "https://localhost:5001;http://localhost:5000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "KestrelStaging": { "commandName": "Project", "launchBrowser": true, "applicationUrl": "https://localhost:5001;http://localhost:5000", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Staging" } } } }
可以通过以下途径选择配置:
dotnet run,使用选项 --launch-profile 设置配置名称。这种方法只支持 Kestrel 配置
dotnet run --launch-profile "SampleApp"
使用 Visual Studio Code 时,环境变量可以在 .vscode/launch.json 文件中设置。下面的示例设置了一些 Host configuration values environment variables:
{ "version": "0.2.0", "configurations": [ { "name": ".NET Core Launch (web)", "type": "coreclr", // Configuration ommitted for brevity. "env": { "ASPNETCORE_ENVIRONMENT": "Development", "ASPNETCORE_URLS": "https://localhost:5001", "ASPNETCORE_DETAILEDERRORS": "1", "ASPNETCORE_SHUTDOWNTIMEOUTSECONDS": "3" }, // Configuration ommitted for brevity.
.vscode/launch.json 文件仅仅被 Visual Studio Code 使用。
生产环境应该配置为最大安全性,性能好(performance),应用程序的健壮性。一些公共的不同于开发环境的设置包括:
使用环境变量或者平台设置用于测试目的设置一个指定的环境通常是有用的。如果环境没有设置,默认是 Production,会禁用大部分的调试特性。设置环境的方法依赖于操作系统。
当主机被创建后,应用程序读取的最后的环境设置决定了应用程序的环境。应用程序的环境在应用程序运行期间不能改变。
示例代码(sample code)中的 About page 展示了 IWebHostEnvironment.EnvironmentName 的值。
通过以下步骤在 Azure App Service 中设置环境:
Azure 应用程序服务会在一个应用程序设置在 Azure portal 中被添加,改变或者删除后重新启动应用程序。
launchSettings.json 中的环境值会覆盖系统环境中的值。
当应用程序使用 dotnet run 启动时,在当前会话中,为了设置 ASPNETCORE_ENVIRONMENT 的值,可以使用下面的命令:
Command prompt
set ASPNETCORE_ENVIRONMENT=Staging dotnet run --no-launch-profile
PowerShell
$Env:ASPNETCORE_ENVIRONMENT = "Staging" dotnet run --no-launch-profile
上面命令中对于 ASPNETCORE_ENVIRONMENT 的设置仅仅对于从命令窗口启动的进程起作用。
在 Windows 中设置全局的值,可以使用以下方法之一:
setx ASPNETCORE_ENVIRONMENT Staging /M
/M 开关表明以系统级别设置环境变量。如果没有使用 /M 开关,环境变量只是设置在当前用户账号下。
PowerShell
[Environment]::SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Staging", "Machine")
Machine 选项的值表明是以系统级别设置环境。如果选项的值更改为 User,环境变量只设置在当前账号下有效。
当 ASPNETCORE_ENVIRONMENT 环境变量是全局设置的,它将会影响在值设置之后打开的任意命令窗口运行命令 dotnet run。launchSettings.json 中的环境的值会覆盖系统环境中的值。
如何使用 web.config 设置 ASPNETCORE_ENVIRONMENT 环境变量,查看 ASP.NET Core Module 中的设置环境变量部分。
对于在 Windows 上使用 IIS 部署:在发布配置文件(publish profile (.pubxml))或者项目文件中包括有 <EnvironmentName> 属性。这种方法会在项目发布的时候在 web.config 文件中设置环境:
<PropertyGroup> <EnvironmentName>Development</EnvironmentName> </PropertyGroup>
对于设置一个在隔离的应用程序池运行(IIS 10.0 或者更新版本支持)的应用程序的 ASPNETCORE_ENVIRONMENT 环境变量,请查看 Environment Variables <environmentVariables> 主题的 AppCmd.exe command 部分。当为一个应用程序池设置 ASPNETCORE_ENVIRONMENT 环境变量时,它会覆盖系统级别的设置。
当在 IIS 中托管一个应用程序时,添加或者更改 ASPNETCORE_ENVIRONMENT 环境变量,可以使用以下的任意一种方法获取新的值:
为 macOS 设置当前环境可以在运行应用程序时执行以下命令:
ASPNETCORE_ENVIRONMENT=Staging dotnet run
或者,在运行应用程序之前使用 export 命令:
export ASPNETCORE_ENVIRONMENT=Staging
Machine-level 的环境变量在 .bashrc 或者 .bash_profile 文件中设置。使用任意的文本编辑器都可以编辑。添加下列语句:
export ASPNETCORE_ENVIRONMENT=Staging
对于 Linux 发行版,在当前会话使用 export 命令设置环境,使用 bash_profile 文件设置 machine-level 的环境设置。
在创建主机的时候调用 UseEnvironment。查看 .NET Generic Host in ASP.NET Core。
通过环境加载配置,请查看 Configuration in ASP.NET Core。
注入 IWebHostEnvironment 到 Startup 的构造方法。这种方法在应用程序在区分只有几个环境,并且代码量很少的情况下,用来配置 Startup 是很有用的。
在下面的例子中:
public class Startup { public Startup(IConfiguration configuration, IWebHostEnvironment env) { Configuration = configuration; _env = env; } public IConfiguration Configuration { get; } private readonly IWebHostEnvironment _env; public void ConfigureServices(IServiceCollection services) { if (_env.IsDevelopment()) { Console.WriteLine(_env.EnvironmentName); } else if (_env.IsStaging()) { Console.WriteLine(_env.EnvironmentName); } else { Console.WriteLine("Not dev or staging"); } services.AddRazorPages(); } public void Configure(IApplicationBuilder app) { if (_env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); }); } }
当一个 ASP.NET Core 应用程序启动时,Startup 类(Startup class )引导应用程序。应用程序可以为不同的环境定义多个 Startup 类。合适的 Startup 类会在运行时被选中。类的名称的前缀匹配了当前环境的类会优先使用。如果一个匹配的 Startup{EnvironmentName} 的类没有被发现,Startup 类会被使用。这种方法在应用程序需要区分每一个环境使用大量代码配置不同环境的启动时非常有用。一般的应用程序不会用到这种方法。
为了实现基于环境的 Startup 类,创建一个 Startup{EnvironmentName} 类和一个备用的 Startup 类:
public class StartupDevelopment { public StartupDevelopment(IConfiguration configuration) { Configuration = configuration; Console.WriteLine(MethodBase.GetCurrentMethod().DeclaringType.Name); } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); } public void Configure(IApplicationBuilder app) { app.UseDeveloperExceptionPage(); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); }); } } public class StartupProduction { public StartupProduction(IConfiguration configuration) { Configuration = configuration; Console.WriteLine(MethodBase.GetCurrentMethod().DeclaringType.Name); } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); } public void Configure(IApplicationBuilder app) { app.UseExceptionHandler("/Error"); app.UseHsts(); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); }); } } public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; Console.WriteLine(MethodBase.GetCurrentMethod().DeclaringType.Name); } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); }); } }
使用重载方法 UseStartup(IWebHostBuilder, String) 接收一个程序集名称:
public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) { var assemblyName = typeof(Startup).GetTypeInfo().Assembly.FullName; return Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(assemblyName); }); } }
Configure 和 ConfigureServices 方法支持特定环境版本的 Configure<EnvironmentName> 和 Configure<Environment>Services。如果匹配的 Configure<Environment>Services 或者 Configure<Environment> 方法没有被发现,ConfigureServices 或者 Configure 方法会被使用。这种方法在应用程序在配置启动时需要使用大量代码来区分每一个环境时是有用的:
public class Startup { private void StartupConfigureServices(IServiceCollection services) { services.AddRazorPages(); } public void ConfigureDevelopmentServices(IServiceCollection services) { MyTrace.TraceMessage(); StartupConfigureServices(services); } public void ConfigureStagingServices(IServiceCollection services) { MyTrace.TraceMessage(); StartupConfigureServices(services); } public void ConfigureProductionServices(IServiceCollection services) { MyTrace.TraceMessage(); StartupConfigureServices(services); } public void ConfigureServices(IServiceCollection services) { MyTrace.TraceMessage(); StartupConfigureServices(services); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { MyTrace.TraceMessage(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); }); } public void ConfigureStaging(IApplicationBuilder app, IWebHostEnvironment env) { MyTrace.TraceMessage(); app.UseExceptionHandler("/Error"); app.UseHsts(); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); }); } } public static class MyTrace { public static void TraceMessage([CallerMemberName] string memberName = "") { Console.WriteLine($"Method: {memberName}"); } }