只有累積,沒有奇蹟

2019年4月16日 星期二

[.NETCore] ASP.NET Core 環境佈署設定 appsettings.json

前言
在上一篇 [.NETCore] ASP.NET Core - ENVIRONMENT 提到了如何設定環境變數值,今天要提的也是與 Configuration 相關的,在開發時往往會因為不同環境讀取不同 Config 的需求,舉例來說如果 Development 與 Staging 環境的資料庫不同時,就會有在不同環境讀取各自的 DB 連線字串設定需求,這篇就介紹如何透過 .NET Core 專案預設的 appsettings.json 在不同環境設定及讀取相對應的組態設定檔資訊,若有問題或是錯誤的地方歡迎各位高手給予指導

appsettings.json 
首先,建立一個 .NET Core Application 應用程式 ( 測試的版本為 2.2 ),在建立完畢之後可以看到專案的 program.cs 預設內容如下
  1. using Microsoft.AspNetCore;
  2. using Microsoft.AspNetCore.Hosting;
  3.  
  4. namespace CoreLabApplication
  5. {
  6. public class Program
  7. {
  8. public static void Main(string[] args)
  9. {
  10. CreateWebHostBuilder(args).Build().Run();
  11. }
  12.  
  13. public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
  14. WebHost.CreateDefaultBuilder(args)
  15. .UseStartup<Startup>();
  16. }
  17. }
在程式主要進入點一開始先呼叫靜態方法  CreateWebHostBuilder ,其內容是新增一個 default 的 Web Host Builder,並建立預設的 Configuration 與 Settings 資訊,在透過  IWebHostBuilder  中的 UseStartup 擴充方法指定 TStartUp 為同樣是內建的 StartUp 類別,接著使用 build 方法建立 WebHost。剛剛提到  CreateWebHostBuilder  會建立預設的 Configuration 資訊,接著我們為了瞭解實作細節透過反射查看此方法骨子裡面做了麼事
  1. /// <summary>
  2. /// Initializes a new instance of the <see cref="T:Microsoft.AspNetCore.Hosting.WebHostBuilder" /> class with pre-configured defaults.
  3. /// </summary>
  4. /// <param name="args">The command line args.</param>
  5. /// <returns>The initialized <see cref="T:Microsoft.AspNetCore.Hosting.IWebHostBuilder" />.</returns>
  6. public static IWebHostBuilder CreateDefaultBuilder(string[] args)
  7. {
  8. WebHostBuilder hostBuilder = new WebHostBuilder();
  9. if (string.IsNullOrEmpty(hostBuilder.GetSetting(WebHostDefaults.ContentRootKey)))
  10. hostBuilder.UseContentRoot(Directory.GetCurrentDirectory());
  11. if (args != null)
  12. hostBuilder.UseConfiguration((IConfiguration) new ConfigurationBuilder().AddCommandLine(args).Build());
  13. hostBuilder.UseKestrel((Action<WebHostBuilderContext, KestrelServerOptions>) ((builderContext, options) => options.Configure((IConfiguration) builderContext.Configuration.GetSection("Kestrel")))).ConfigureAppConfiguration((Action<WebHostBuilderContext, IConfigurationBuilder>) ((hostingContext, config) =>
  14. {
  15. IHostingEnvironment hostingEnvironment = hostingContext.HostingEnvironment;
  16.  
  17. config.AddJsonFile("appsettings.json", true, true)
  18. .AddJsonFile("appsettings." + hostingEnvironment.EnvironmentName + ".json", true, true);
  19.  
  20. if (hostingEnvironment.IsDevelopment())
  21. {
  22. Assembly assembly = Assembly.Load(new AssemblyName(hostingEnvironment.ApplicationName));
  23. if (assembly != (Assembly) null)
  24. config.AddUserSecrets(assembly, true);
  25. }
  26. config.AddEnvironmentVariables();
  27. if (args == null)
  28. return;
  29. config.AddCommandLine(args);
  30. })).ConfigureLogging((Action<WebHostBuilderContext, ILoggingBuilder>) ((hostingContext, logging) =>
  31. {
  32. logging.AddConfiguration((IConfiguration) hostingContext.Configuration.GetSection("Logging"));
  33. logging.AddConsole();
  34. logging.AddDebug();
  35. logging.AddEventSourceLogger();
  36. })).ConfigureServices((Action<WebHostBuilderContext, IServiceCollection>) ((hostingContext, services) =>
  37. {
  38. services.PostConfigure<HostFilteringOptions>((Action<HostFilteringOptions>) (options =>
  39. {
  40. if (options.AllowedHosts != null && options.AllowedHosts.Count != 0)
  41. return;
  42. string str = hostingContext.Configuration["AllowedHosts"];
  43. string[] strArray1;
  44. if (str == null)
  45. strArray1 = (string[]) null;
  46. else
  47. strArray1 = str.Split(new char[1]{ ';' }, StringSplitOptions.RemoveEmptyEntries);
  48. string[] strArray2 = strArray1;
  49. HostFilteringOptions filteringOptions = options;
  50. string[] strArray3;
  51. if (strArray2 == null || strArray2.Length == 0)
  52. strArray3 = new string[1]{ "*" };
  53. else
  54. strArray3 = strArray2;
  55. filteringOptions.AllowedHosts = (IList<string>) strArray3;
  56. }));
  57. services.AddSingleton<IOptionsChangeTokenSource<HostFilteringOptions>>((IOptionsChangeTokenSource<HostFilteringOptions>) new ConfigurationChangeTokenSource<HostFilteringOptions>(hostingContext.Configuration));
  58. services.AddTransient<IStartupFilter, HostFilteringStartupFilter>();
  59. })).UseIIS().UseIISIntegration().UseDefaultServiceProvider((Action<WebHostBuilderContext, ServiceProviderOptions>) ((context, options) => options.ValidateScopes = context.HostingEnvironment.IsDevelopment()));
  60. return (IWebHostBuilder) hostBuilder;
  61. }
透過反射可以得知主要是建立一個 WebHostBuilder 並定義相關設定初始值,由於代碼細節過多因此整理  CreateWebHostBuilder  方法重點如下

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 )大多都要自行撰寫下列代碼
  1. var builder = new ConfigurationBuilder()
  2. .SetBasePath(env.ContentRootPath)
  3. .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
  4. .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
  5. .Build();
在.NET Core 2.1 之後則提供靜態方法  CreateWebHostBuilder  將常用 Configuration 做設定,詳細可以參考 Migrate from ASP.NET Core 2.0 to 2.1

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 : 加上以下代碼

  1. <ItemGroup>
  2. <Content Include="appsettings.json">
  3. <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  4. </Content>
  5. <Content Include="appsettings.Development.json;appsettings.Production.json">
  6. <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  7. <DependentUpon>appsettings.json</DependentUpon>
  8. </Content>
  9. </ItemGroup>
設定完成 !!! 設定成功畫面如下

心得
在查詢 appsettings 相關文章時大多都還是舊語法相關的資料,且日期多為 2018 年中左右,沒一年的時間就已經出新的語法版本從 2.1 到目前的最新的 3.0 preview,目前在查詢相關文件時還是以 MSDN 為主,避免得到錯誤的資訊造成誤判,希望自己可以盡快補齊 .NET Core 相關資訊,繼續努力往自己的目標邁進 :)

參考
ASP.NET Core 的設定
What is the difference between IWebHost WebHostBuilder BuildWebHost

Related Posts:

  • [VisualStudio] .NET 分析測試代碼覆蓋率 AxoCover前言  最近在替既有專案補上單元測試,除了在 SonarQube 可以看到測試代碼覆蓋率之外,這幾天同事推薦一套可以在 Visual Studio 執行的程式碼覆蓋率分析工具 AxoCover,可運行在 .NET 環境且開源免費,簡單玩了一下覺得十分不錯推薦給大家,今天就來分享 AxoCover 在 Visual Studio 2017 的安裝及基本操作說明。 安裝 AxoCover  Step 1 :… Read More
  • [IIS] IIS 站台服務異常中止 - HttpEvent 問題 今天同事反應測試主機 IIS Server 無法使用,進到 QA 主機後發現所有的 IIS 服務都已停止,第一直覺就是到事件檢視器查看是否有異常的 Log 資訊,發現事件檢視器紀錄其中來源  HttpEvent  嫌疑重大,以下就針對解決此問題的方式做說明,若有問題歡迎提出一起討論或是給予指導。 解決方案 由於公司測試機對外預設都是以 80 port 為主,無故發生異常是蠻很奇怪,過去… Read More
  • [.NET] 字串加密 MD5、SHA1 常在開發中遇到需要將特定資料加密的動作,在儲存到資料庫中(比如說網站用戶的密碼加密後存到資料庫中,用戶在登入時,在把用戶輸入的密碼進行加密,再與資料庫密碼欄位比較是否一致)在.NET Framework中,可以透過 System.Security.Cryptography 命名空間來產生加密演算法的金鑰(註一),在用雜湊值(Hash Value)的加密方式達到目的,雜湊演算法將任意長度的二進位值對應到固定長度較小的二進位值,稱為雜湊值 (Ha… Read More
  • [C#] Array陣列中加入元素 前言 此篇文章是要記錄 如何在Array陣列中加入元素 ( 之前是 如何移除 Array 陣列中指定的元素 ) 查了一下MSDN Array 陣列成員 不提供add的方法加入新的元素 但仔細看了一下成員中的方法,可以發現有個公用方法 Array.Resize 方法說明:將陣列的大小變更為指定之新大小 雖然沒有add方法,但也可以用 array.resize… Read More
  • [UnitTest] 如何測試目標方法中 Guid 型別的代碼 ?情境 如果要產生一個亂數時很常會想到 Guid 方法解決,在 C# 使用 Guid 的方式相當簡單僅要透過  Guid.NewGuid  靜態方法產生一組 Guid 使用,在目前公司很常看到使用 Guid 作為識別碼,今天在重構舊代碼時忽然想到如果遇到 Guid 該如何進行加上單元測試,以下就目前想到的解法進行測試與說明,如果各位高手們有更好的方法歡迎高抬貴手一起討論研究。 解決方案 寫個簡單的 Sa… Read More

0 意見:

張貼留言

Copyright © 2025 m@rcus 學習筆記 | Powered by Blogger

Design by Anders Noren | Blogger Theme by NewBloggerThemes.com