多環境開發
本篇將演示Asp.Net Core如何在多環境下進行開發適配。
在一個正規的開發流程里,軟件開發部署將要經過三個階段:開發、測試、上線,對應了三個環境:開發、測試、生產。在不同的環境里,需要編寫不同的代碼,比如,在開發環境里,為了方便開發和調試,前段js文件和css文件不會被壓縮,異常信息將會暴露得更加明顯,緩存一般也不會使用等等。而在測試環境里,為了更加接近生產環境,在開發采取的調試手段將會被屏蔽,同時為了能更好的測試發現問題,通常也會添加一些測試專用的服務和代碼。最終在生產環境上,因為高效性、容錯和友好性或者安全性等原因,某些功能會被屏蔽,某些功能將會被更加謹慎或者有效的手段代替。在這種情況下,需要能通過某種手段,使一套代碼在不同環境下部署時能體現不同的特性。
第一部分、多環境標識
在.Net Core里,通過一個特殊的環境變量: ASPNETCORE_ENVIRONMENT 來標識多環境,默認情況下,會有下面三個值
- Development:開發
- Staging:預發布
- Production:生產
借助不同的開發工具進行調試時,會有不同的配置方式。
在Visual Studio Code里:
在 launch.json 里配置 ASPNETCORE_ENVIRONMENT 的值,這個文件在工程目錄下的.vscode目錄里,這個目錄和里面的文件是在VS Code里開發調試時特有的。
1 {
2 "version": "0.2.0",
3 "configurations": [
4 {
5 "name": ".NET Core Launch (console)",
6 "type": "coreclr",
7 "request": "launch",
8 "preLaunchTask": "build",
9 "program": "${workspaceRoot}/bin/Debug/netcoreapp1.0/WebApiFrame.dll",
10 "args": [],
11 "cwd": "${workspaceRoot}",
12 "stopAtEntry": false,
13 "externalConsole": false,
14 "env": {
15 "ASPNETCORE_ENVIRONMENT": "Development"
16 }
17 },
18 {
19 "name": ".NET Core Launch (web)",
20 "type": "coreclr",
21 "request": "launch",
22 "preLaunchTask": "build",
23 "program": "${workspaceRoot}/bin/Debug/netcoreapp1.0/WebApiFrame.dll",
24 "args": [],
25 "cwd": "${workspaceRoot}",
26 "stopAtEntry": false,
27 "launchBrowser": {
28 "enabled": true,
29 "args": "${auto-detect-url}",
30 "windows": {
31 "command": "cmd.exe",
32 "args": "/C start ${auto-detect-url}"
33 },
34 "osx": {
35 "command": "open"
36 },
37 "linux": {
38 "command": "xdg-open"
39 }
40 },
41 "env": {
42 "ASPNETCORE_ENVIRONMENT": "Development"
43 }
44 },
45 {
46 "name": ".NET Core Attach",
47 "type": "coreclr",
48 "request": "attach",
49 "processId": 0
50 }
51 ]
52 }
在這個配置文件的configurations節點下有兩個json對象,分別對應着三種不同的啟動方式,前兩個分別對應着控制台啟動和Web瀏覽器啟動,最后一個采用附加進程的方式啟動。
在前兩種方式的配置里都有一個名字叫env的節點,節點里將配置 ASPNETCORE_ENVIRONMENT 的值。當采用這兩種的任意一種方式啟動時,可以看到控制台里將顯示當前程序的環境標識。如果不配置這個環境變量,默認將是Production。

在Visual Studio 2015里:
在 launchSettings.json 里配置 ASPNETCORE_ENVIRONMENT 的值。這個文件在工程目錄下的Properties文件夾里。這個文件夾和里面的文件也是在VS2015開發調試時里特有的。
1 {
2 "iisSettings": {
3 "windowsAuthentication": false,
4 "anonymousAuthentication": true,
5 "iisExpress": {
6 "applicationUrl": "http://localhost:11974/",
7 "sslPort": 0
8 }
9 },
10 "profiles": {
11 "IIS Express": {
12 "commandName": "IISExpress",
13 "launchBrowser": true,
14 "launchUrl": "api/values",
15 "environmentVariables": {
16 "ASPNETCORE_ENVIRONMENT": "Development"
17 }
18 },
19 "ExampleTest": {
20 "commandName": "Project",
21 "launchBrowser": true,
22 "launchUrl": "http://localhost:5000/",
23 "environmentVariables": {
24 "ASPNETCORE_ENVIRONMENT": "Development"
25 }
26 }
27 }
28 }
同樣,這個文件也描述了兩種啟動調試的方式:IIS宿主啟動和控制台啟動,每種方式里都有一個environmentVariables節點,節點里將配置 ASPNETCORE_ENVIRONMENT 的值。
另外,在VS2015里也可以通過項目的屬性可視化界面進行配置,最終的效果會同步修改 launchSettings.json 文件內容

在cmd窗口控制台里:
當使用cmd窗口進行啟動時,可以使用下面的命令進行設置

通過 set 命令設置環境變量 ASPNETCORE_ENVIRONMENT 的值,然后通過 dotnet run 啟動。
也可以通過設置當前機器的環境變量。設置好后需要重新打開cmd窗口,將環境變量讀取到當前環境里。

第二部分、多環境判斷
在.Net Core里,通過 IHostingEnvironment 接口來獲取 ASPNETCORE_ENVIRONMENT 變量的相關信息。這個接口通過依賴注入的方式獲取對應的實例對象。
1 using System.IO;
2 using Microsoft.AspNetCore.Builder;
3 using Microsoft.AspNetCore.Hosting;
4 using Microsoft.Extensions.Configuration;
5 using Microsoft.Extensions.DependencyInjection;
6 using Microsoft.Extensions.Logging;
7
8 namespace WebApiFrame
9 {
10 public class Startup
11 {
12 public IConfiguration Configuration { get; }
13
14 public Startup(IHostingEnvironment env)
15 {
16 var builder = new ConfigurationBuilder()
17 .SetBasePath(Directory.GetCurrentDirectory())
18 .AddJsonFile("appsettings.json");
19
20 Configuration = builder.Build();
21
22 System.Console.WriteLine($"Current State: {env.EnvironmentName}");
23 System.Console.WriteLine($"Development State: {env.IsDevelopment()}");
24 System.Console.WriteLine($"Staging State: {env.IsStaging()}");
25 System.Console.WriteLine($"Production State: {env.IsProduction()}");
26 }
27
28 public void ConfigureServices(IServiceCollection services)
29 {
30 services.AddOptions();
31 services.Configure<ConfigOptions>(Configuration.GetSection("CfgContent"));
32
33 // 注入MVC框架
34 services.AddMvc();
35 }
36
37 public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IHostingEnvironment env)
38 {
39 // 添加日志支持
40 loggerFactory.AddConsole(Configuration.GetSection("Logging"));
41 loggerFactory.AddDebug();
42
43 // 添加NLog日志支持
44 //loggerFactory.AddNLog();
45
46 // 添加MVC中間件
47 app.UseMvc();
48 }
49 }
50 }
上面的代碼在VS Code里調試時控制台輸出的效果如下

在 Startup.cs 類里, IHostingEnvironment 接口可以作為構造函數和Configure方法的參數,通過依賴注入的方式獲取實例。
通過實例的EnvironmentName屬性可以獲取到 ASPNETCORE_ENVIRONMENT 環境變量的值,同時也可以通過IsDevelopment、IsStaging和IsProduction方法快速判斷屬性值。
另外,也可以通過以下另外一種方式根據 ASPNETCORE_ENVIRONMENT 環境變量的值執行不同的代碼
1 using System.IO;
2 using Microsoft.AspNetCore.Builder;
3 using Microsoft.AspNetCore.Hosting;
4 using Microsoft.AspNetCore.Http;
5 using Microsoft.Extensions.Configuration;
6 using Microsoft.Extensions.DependencyInjection;
7 using Microsoft.Extensions.Logging;
8
9 namespace WebApiFrame
10 {
11 public class Startup
12 {
13 public IConfiguration Configuration { get; }
14
15 public Startup(IHostingEnvironment env)
16 {
17 var builder = new ConfigurationBuilder()
18 .SetBasePath(Directory.GetCurrentDirectory())
19 .AddJsonFile("appsettings.json");
20
21 Configuration = builder.Build();
22
23 System.Console.WriteLine($"Current State: {env.EnvironmentName}");
24 }
25
26 // Development環境下執行的ConfigureServices方法
27 public void ConfigureDevelopmentServices(IServiceCollection services)
28 {
29 System.Console.WriteLine($"ConfigureDevelopmentServices Excuted.");
30 }
31
32 // Development環境下執行的Configure方法
33 public void ConfigureDevelopment(IApplicationBuilder app, ILoggerFactory loggerFactory, IHostingEnvironment env)
34 {
35 app.Run(async context =>
36 {
37 await context.Response.WriteAsync("ConfigureDevelopment Excuted.");
38 });
39 }
40
41 public void ConfigureServices(IServiceCollection services)
42 {
43 services.AddOptions();
44 services.Configure<ConfigOptions>(Configuration.GetSection("CfgContent"));
45
46 // 注入MVC框架
47 services.AddMvc();
48 }
49
50 public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, IHostingEnvironment env)
51 {
52 // 添加日志支持
53 loggerFactory.AddConsole(Configuration.GetSection("Logging"));
54 loggerFactory.AddDebug();
55
56 // 添加NLog日志支持
57 //loggerFactory.AddNLog();
58
59 // 添加MVC中間件
60 app.UseMvc();
61 }
62 }
63 }
啟動調試,訪問地址 http://localhost:5000/ ,查看控制台日志和頁面內容


可以看到,通過特殊方法名 Configure{ASPNETCORE_ENVIRONMENT}Services 和 Configure{ASPNETCORE_ENVIRONMENT} 可以在不同的環境變量下執行不同的代碼。

