ASP .NET CORE 根據環境變數支援多個 appsettings.json

語言: CN / TW / HK

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_ENVIRONMENT=Production --name testContainer testImage

__EOF__

  • 本文作者: MyZony

  • 本文連結: https://www.cnblogs.com/myzony/p/9418858.html

  • 關於博主: 評論和私信會在第一時間回覆。或者直接私信我。

  • 版權宣告: 本部落格所有文章除特別宣告外,均採用 BY-NC-SA 許可協議。轉載請註明出處!

  • 聲援博主: 如果您覺得文章對您有幫助,可以點選文章右下角 【推薦】 一下。