在上一篇 [.NETCore] ASP.NET Core - ENVIRONMENT 提到了如何設定環境變數值,今天要提的也是與 Configuration 相關的,在開發時往往會因為不同環境讀取不同 Config 的需求,舉例來說如果 Development 與 Staging 環境的資料庫不同時,就會有在不同環境讀取各自的 DB 連線字串設定需求,這篇就介紹如何透過 .NET Core 專案預設的 appsettings.json 在不同環境設定及讀取相對應的組態設定檔資訊,若有問題或是錯誤的地方歡迎各位高手給予指導。
appsettings.json
首先,建立一個 .NET Core Application 應用程式 ( 測試的版本為 2.2 ),在建立完畢之後可以看到專案的 program.cs 預設內容如下
- using Microsoft.AspNetCore;
- using Microsoft.AspNetCore.Hosting;
- namespace CoreLabApplication
- {
- public class Program
- {
- public static void Main(string[] args)
- {
- CreateWebHostBuilder(args).Build().Run();
- }
- public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
- WebHost.CreateDefaultBuilder(args)
- .UseStartup<Startup>();
- }
- }
在程式主要進入點一開始先呼叫靜態方法 CreateWebHostBuilder ,其內容是新增一個 default 的 Web Host Builder,並建立預設的 Configuration 與 Settings 資訊,在透過 IWebHostBuilder 中的 UseStartup 擴充方法指定 TStartUp 為同樣是內建的 StartUp 類別,接著使用 build 方法建立 WebHost。剛剛提到 CreateWebHostBuilder 會建立預設的 Configuration 資訊,接著我們為了瞭解實作細節透過反射查看此方法骨子裡面做了麼事
appsettings.json 預設配置檔案
- config.AddJsonFile("appsettings.json", true, true)
首先 config Provider 來源設定為 Json 格式,並使用內建的 appsettings.json 作為 config 來源,並定義 reloadOnChange 為 true,也就是當檔案內容更新時後會重新載入。
- AddJsonFile("appsettings." + hostingEnvironment.EnvironmentName + ".json", true, true);
接著會在使用環境變數尋找相關環境設定檔,如果存在就覆蓋原本的預設值,舉例來說,在 Development 環境底下,此代碼就會尋找根目錄中是否存在 appsettings.Development.json 檔案,如果 appsettings.json 與 appsettings.Development.json 有設定值相同時,會以後面的值為主 (覆蓋前者)。
備註 : 在 .NET Core 2.1 後的版本使用 IWebHostBuilder 取代既有的 IWebHost 方式,在過去如果要根據環境讀取相關 appsettings.json 資訊 ( 或是 Console )大多都要自行撰寫下列代碼
Configuration 載入順序
在 .NET Core 中提供不同 Provider 方式讀取/載入相關設定資訊,舉例來說在上述代碼中就可以看到有用到 CommandLine、Environment Variable、File (.Json)、UserSecrets 等多種方式,如果在自訂時也可以參考此種設定,詳細可以參考 MSDN 說明 : 傳送門,雖然有多種載入 Configuration 的方式,但讀取的優先順序也是很重要的,在啟動時後面載入的會將前者重複定義的覆蓋掉,因此在 Configuration 載入時載入順序如下
新增設定 透過反射可以得知主要是建立一個 WebHostBuilder 並定義相關設定初始值,由於代碼細節過多因此整理 CreateWebHostBuilder 方法重點如下
- /// <summary>
- /// Initializes a new instance of the <see cref="T:Microsoft.AspNetCore.Hosting.WebHostBuilder" /> class with pre-configured defaults.
- /// </summary>
- /// <param name="args">The command line args.</param>
- /// <returns>The initialized <see cref="T:Microsoft.AspNetCore.Hosting.IWebHostBuilder" />.</returns>
- public static IWebHostBuilder CreateDefaultBuilder(string[] args)
- {
- WebHostBuilder hostBuilder = new WebHostBuilder();
- if (string.IsNullOrEmpty(hostBuilder.GetSetting(WebHostDefaults.ContentRootKey)))
- hostBuilder.UseContentRoot(Directory.GetCurrentDirectory());
- if (args != null)
- hostBuilder.UseConfiguration((IConfiguration) new ConfigurationBuilder().AddCommandLine(args).Build());
- hostBuilder.UseKestrel((Action<WebHostBuilderContext, KestrelServerOptions>) ((builderContext, options) => options.Configure((IConfiguration) builderContext.Configuration.GetSection("Kestrel")))).ConfigureAppConfiguration((Action<WebHostBuilderContext, IConfigurationBuilder>) ((hostingContext, config) =>
- {
- IHostingEnvironment hostingEnvironment = hostingContext.HostingEnvironment;
- config.AddJsonFile("appsettings.json", true, true)
- .AddJsonFile("appsettings." + hostingEnvironment.EnvironmentName + ".json", true, true);
- if (hostingEnvironment.IsDevelopment())
- {
- Assembly assembly = Assembly.Load(new AssemblyName(hostingEnvironment.ApplicationName));
- if (assembly != (Assembly) null)
- config.AddUserSecrets(assembly, true);
- }
- config.AddEnvironmentVariables();
- if (args == null)
- return;
- config.AddCommandLine(args);
- })).ConfigureLogging((Action<WebHostBuilderContext, ILoggingBuilder>) ((hostingContext, logging) =>
- {
- logging.AddConfiguration((IConfiguration) hostingContext.Configuration.GetSection("Logging"));
- logging.AddConsole();
- logging.AddDebug();
- logging.AddEventSourceLogger();
- })).ConfigureServices((Action<WebHostBuilderContext, IServiceCollection>) ((hostingContext, services) =>
- {
- services.PostConfigure<HostFilteringOptions>((Action<HostFilteringOptions>) (options =>
- {
- if (options.AllowedHosts != null && options.AllowedHosts.Count != 0)
- return;
- string str = hostingContext.Configuration["AllowedHosts"];
- string[] strArray1;
- if (str == null)
- strArray1 = (string[]) null;
- else
- strArray1 = str.Split(new char[1]{ ';' }, StringSplitOptions.RemoveEmptyEntries);
- string[] strArray2 = strArray1;
- HostFilteringOptions filteringOptions = options;
- string[] strArray3;
- if (strArray2 == null || strArray2.Length == 0)
- strArray3 = new string[1]{ "*" };
- else
- strArray3 = strArray2;
- filteringOptions.AllowedHosts = (IList<string>) strArray3;
- }));
- services.AddSingleton<IOptionsChangeTokenSource<HostFilteringOptions>>((IOptionsChangeTokenSource<HostFilteringOptions>) new ConfigurationChangeTokenSource<HostFilteringOptions>(hostingContext.Configuration));
- services.AddTransient<IStartupFilter, HostFilteringStartupFilter>();
- })).UseIIS().UseIISIntegration().UseDefaultServiceProvider((Action<WebHostBuilderContext, ServiceProviderOptions>) ((context, options) => options.ValidateScopes = context.HostingEnvironment.IsDevelopment()));
- return (IWebHostBuilder) hostBuilder;
- }
appsettings.json 預設配置檔案
- config.AddJsonFile("appsettings.json", true, true)
首先 config Provider 來源設定為 Json 格式,並使用內建的 appsettings.json 作為 config 來源,並定義 reloadOnChange 為 true,也就是當檔案內容更新時後會重新載入。
- AddJsonFile("appsettings." + hostingEnvironment.EnvironmentName + ".json", true, true);
接著會在使用環境變數尋找相關環境設定檔,如果存在就覆蓋原本的預設值,舉例來說,在 Development 環境底下,此代碼就會尋找根目錄中是否存在 appsettings.Development.json 檔案,如果 appsettings.json 與 appsettings.Development.json 有設定值相同時,會以後面的值為主 (覆蓋前者)。
備註 : 在 .NET Core 2.1 後的版本使用 IWebHostBuilder 取代既有的 IWebHost 方式,在過去如果要根據環境讀取相關 appsettings.json 資訊 ( 或是 Console )大多都要自行撰寫下列代碼
在.NET Core 2.1 之後則提供靜態方法 CreateWebHostBuilder 將常用 Configuration 做設定,詳細可以參考 Migrate from ASP.NET Core 2.0 to 2.1
- var builder = new ConfigurationBuilder()
- .SetBasePath(env.ContentRootPath)
- .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
- .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
- .Build();
Configuration 載入順序
在 .NET Core 中提供不同 Provider 方式讀取/載入相關設定資訊,舉例來說在上述代碼中就可以看到有用到 CommandLine、Environment Variable、File (.Json)、UserSecrets 等多種方式,如果在自訂時也可以參考此種設定,詳細可以參考 MSDN 說明 : 傳送門,雖然有多種載入 Configuration 的方式,但讀取的優先順序也是很重要的,在啟動時後面載入的會將前者重複定義的覆蓋掉,因此在 Configuration 載入時載入順序如下
- File 檔案
- Azure Key Vault
- User Secrets ( 僅 Development 環境 )
- 環境變數
- 命令列
透過以上詳細說明,可以得知如果要設定不同環境的設定檔時,僅需要加上 appsettings.{環境變數}.json 即可,就可以透過內建的組態設定機制來區分環境,取得 appsettings.json 方式之前有介紹過,這裡就不在多加說明,詳細可以參考 傳送門,下列為新增 Development 與 Production 範例
縮排設定
如果想要調整 appsettings.json 縮排將前墜詞相同的放一起,可以透過以下步驟調整
Step 1 : 開啟 Visual Studio 2019,在專案上滑鼠 double click 開啟專案 csproj
Step 2 : 加上以下代碼
設定完成 !!! 設定成功畫面如下
- <ItemGroup>
- <Content Include="appsettings.json">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- </Content>
- <Content Include="appsettings.Development.json;appsettings.Production.json">
- <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
- <DependentUpon>appsettings.json</DependentUpon>
- </Content>
- </ItemGroup>
心得
在查詢 appsettings 相關文章時大多都還是舊語法相關的資料,且日期多為 2018 年中左右,沒一年的時間就已經出新的語法版本從 2.1 到目前的最新的 3.0 preview,目前在查詢相關文件時還是以 MSDN 為主,避免得到錯誤的資訊造成誤判,希望自己可以盡快補齊 .NET Core 相關資訊,繼續努力往自己的目標邁進 :)
參考
ASP.NET Core 的設定
What is the difference between IWebHost WebHostBuilder BuildWebHost
0 意見:
張貼留言