0.背景 在開發項目的過程當中,生產環境與調試環境的配置肯定是不一樣的。拿個最簡單的例子來說,比如連接字元串這種東西,調試環境肯定是不能連接生產資料庫的。在之前的話,這種情況只能說是你 COPY 兩個同名的配置文件來進行處理。然後你在本地就使用本地的配置,生產環境就使用生產環境的配置文件,十分麻煩。 ...
0.背景
在開發項目的過程當中,生產環境與調試環境的配置肯定是不一樣的。拿個最簡單的例子來說,比如連接字元串這種東西,調試環境肯定是不能連接生產資料庫的。在之前的話,這種情況只能說是你 COPY 兩個同名的配置文件來進行處理。然後你在本地就使用本地的配置,生產環境就使用生產環境的配置文件,十分麻煩。
而 ASP .NET CORE 支持利用環境變數來動態配置 JSON 文件,下麵就來看一下吧。
1.準備工作
首先在你的 ASP .NET CORE 項目當中添加一個 appsettings.json
文件,內容如下:
{
"ConnectionString": {
"Default": "Normal Database"
}
}
之後再繼續添加一個 appsettings.Development.json
,之後在你的解決方案管理器就會看到下麵這種情況。
更改其內容如下:
{
"ConnectionString": {
"Default": "Development Database"
}
}
之後呢,我們繼續添加一個生產環境的配置文件,名字叫做 appsettings.Production.json
,更改其內容如下:
{
"ConnectionString": {
"Default": "Production Database"
}
}
最後我們的文件應該如下圖:
以上就是我們的準備工作,我們準備了兩個環境的配置文件以及一個預設情況的配置文件,下麵我就就來看看如何應用環境變數來達到我們想要的效果。
2.環境控制
在項目調試的時候,我們可以通過右鍵項目屬性,跳轉到調試可以看到一個環境變數的設定,通過更改 ASPNETCORE_ENVIRONMENT
的值來切換不同環境。
可以看到目前我們處於 Development
也就是開發環境,那麼按照我們的設想,就應該讀取 appsettings.Development.json
的文件數據了。
2.編寫代碼
新建一個 AppConfigure
靜態類,他的內部有一個字典,用於緩存不同環境不同路徑的 IConfigurationRoot
配置。
public static class AppConfigure
{
// 緩存字典
private static readonly ConcurrentDictionary<string, IConfigurationRoot> _cacheDict;
static AppConfigure()
{
_cacheDict = new ConcurrentDictionary<string, IConfigurationRoot>();
}
// 傳入 JSON 文件夾路徑與當前的環境變數值
public static IConfigurationRoot GetConfigurationRoot(string jsonDir, string environmentName = null)
{
// 設置緩存的 KEY
var cacheKey = $"{jsonDir}#{environmentName}";
// 添加預設的 JSON 配置
var builder = new ConfigurationBuilder().SetBasePath(jsonDir).AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
// 根據環境變數添加相應的 JSON 配置文件
if (!string.IsNullOrEmpty(environmentName))
{
builder = builder.AddJsonFile($"appsettings.{environmentName}.json", optional: true, reloadOnChange: true);
}
// 返回構建成功的 IConfigurationRoot 對象
return builder.Build();
}
}
用法的話也很簡單:
public Startup(IHostingEnvironment env)
{
var configurationRoot = AppConfigure.GetConfigurationRoot(env.ContentRootPath, env.EnvironmentName);
Console.WriteLine(configurationRoot["ConnectionString:Default"]);
}
3.測試
測試的話直接更改環境變數就可以看到效果了,更改其值為 Production。
現在我們來運行,並且添加一個監視變數。
看樣子它現在讀取的就是我們的生產環境的數據了。
4.代碼分析
其實吧,也不用這麼麻煩,在 Startup.cs
通過構造註入得到的 IConfiguration
就是按照 GetConfigurationRoot()
這個方法來進行構建的,你直接使用 Configuration/ConfigurationRoot
的索引器就可以訪問到與環境變數相應的 JSON 文件了。
可能你還不太理解,明明在 GetConfigurationRoot()
方法裡面使用 AddJsonFile()
方法只是添加了兩次個 Provider ,為什麼在使用索引器訪問 JSON 配置的時候就是使用的當前環境的 JSON 文件呢?
我其實以為最開始 .NET CORE 對於 IConfiguration
的索引器實現就是讀取了當前環境變數,然後根據這個環境變數去匹配對應的 Provider 取得值。
最後翻閱了 .NET CORE 的源代碼之後發現是我想錯了,其實他就是單純的翻轉了一下 Providers 的集合,然後取的第一個元素。
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Microsoft.Extensions.Primitives;
namespace Microsoft.Extensions.Configuration
{
public class ConfigurationRoot : IConfigurationRoot
{
private IList<IConfigurationProvider> _providers;
private ConfigurationReloadToken _changeToken = new ConfigurationReloadToken();
// 初始化 ConfigurationRoot 的時候傳入配置提供者
public ConfigurationRoot(IList<IConfigurationProvider> providers)
{
if (providers == null)
{
throw new ArgumentNullException(nameof(providers));
}
_providers = providers;
foreach (var p in providers)
{
p.Load();
ChangeToken.OnChange(() => p.GetReloadToken(), () => RaiseChanged());
}
}
public IEnumerable<IConfigurationProvider> Providers => _providers;
public string this[string key]
{
get
{
// 反轉 Providers ,之後遍歷
foreach (var provider in _providers.Reverse())
{
string value;
// 如果拿到了值,直接返回,不再遍歷
if (provider.TryGet(key, out value))
{
return value;
}
}
return null;
}
set
{
if (!_providers.Any())
{
throw new InvalidOperationException(Resources.Error_NoSources);
}
foreach (var provider in _providers)
{
provider.Set(key, value);
}
}
}
}
// ... 省略了的代碼
}
回到第三節所寫的代碼,可以看到我們首先添加的是 appsettings.json
然後再根據環境變數添加的 $"appsettings.{environmentName}.json"
,所以反轉之後取得的肯定就是帶環境變數的配置文件咯。
5.不同 OS 的環境變數配置
5.1 Windows
直接右鍵電腦手動添加環境變數。
5.2 Linux
使用 export 命令直接進行環境變數設置。
export ASPNETCORE_ENVIRONMEN='Production'
5.3 Docker
Docker 配置最為簡單,直接在啟動容器的時候加上 -e
參數即可,例如:
docker run -d -e ASPNETCORE_ENVIRONMEN=Production --name testContainer testImage