在開發項目的過程中,生產環境與調試環境的配置確定是不同的。拿個最簡單的例子來講,好比鏈接字符串這種東西,調試環境確定是不能鏈接生產數據庫的。在以前的話,這種狀況只能說是你 COPY 兩個同名的配置文件來進行處理。而後你在本地就使用本地的配置,生產環境就使用生產環境的配置文件,十分麻煩。linux
而 ASP .NET CORE 支持利用環境變量來動態配置 JSON 文件,下面就來看一下吧。docker
首先在你的 ASP .NET CORE 項目當中添加一個 appsettings.json
文件,內容以下:shell
{ "ConnectionString": { "Default": "Normal Database" } }
以後再繼續添加一個 appsettings.Development.json
,以後在你的解決方案管理器就會看到下面這種狀況。數據庫
更改其內容以下:json
{ "ConnectionString": { "Default": "Development Database" } }
以後呢,咱們繼續添加一個生產環境的配置文件,名字叫作 appsettings.Production.json
,更改其內容以下:windows
{ "ConnectionString": { "Default": "Production Database" } }
最後咱們的文件應該以下圖:緩存
以上就是咱們的準備工做,咱們準備了兩個環境的配置文件以及一個默認狀況的配置文件,下面我就就來看看如何應用環境變量來達到咱們想要的效果。app
在項目調試的時候,咱們能夠經過右鍵項目屬性,跳轉到調試能夠看到一個環境變量的設定,經過更改 ASPNETCORE_ENVIRONMENT
的值來切換不一樣環境。ide
能夠看到目前咱們處於 Development
也就是開發環境,那麼按照咱們的設想,就應該讀取 appsettings.Development.json
的文件數據了。測試
新建一個 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"]); }
測試的話直接更改環境變量就能夠看到效果了,更改其值爲 Production。
如今咱們來運行,而且添加一個監視變量。
看樣子它如今讀取的就是咱們的生產環境的數據了。
其實吧,也不用這麼麻煩,在 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"
,因此反轉以後取得的確定就是帶環境變量的配置文件咯。
直接右鍵計算機手動添加環境變量。
使用 export 命令直接進行環境變量設置。
export ASPNETCORE_ENVIRONMEN='Production'
Docker 配置最爲簡單,直接在啓動容器的時候加上 -e
參數便可,例如:
docker run -d -e ASPNETCORE_ENVIRONMENT=Production --name testContainer testImage