.NET Core 3.0之深入源碼理解Configuration(二)

来源:https://www.cnblogs.com/edison0621/archive/2019/05/19/10889325.html
-Advertisement-
Play Games

文件型配置基本內容 上一篇文章討論了Configuration的幾個核心對象,本文繼續討論Configuration中關於文件型配置的相關內容。相比較而言,文件型配置的使用場景更加廣泛,用戶自定義配置擴展也可以基於文件型配置進行擴展。如果需要查看上一篇文章,可以點擊移步。 .NET Core文件型配 ...


 

文件型配置基本內容

上一篇文章討論了Configuration的幾個核心對象,本文繼續討論Configuration中關於文件型配置的相關內容。相比較而言,文件型配置的使用場景更加廣泛,用戶自定義配置擴展也可以基於文件型配置進行擴展。如果需要查看上一篇文章,可以點擊移步

.NET Core文件型配置中我們提供了三種主要的實現,分別是JSON、XML、INI,請查看下圖

file2

由圖可知,這三種配置的實現方式是一樣的,當然了其他的配置比如命令行配置、環境變數配置等也是大同小異,理解了改配置類型的實現方式,後面我們再擴展基於Consul或者ZK的實現,就非常簡單了。

文件型配置的抽象擴展

文件型配置的抽象擴展位於Microsoft.Extensions.Configuration.FileExtensions組件中,該擴展是一個基礎實現。不過其命名空間是Microsoft.Extensions.Configuration,而Micros oft.Extensions.Configuration擴建本身又是整個.NET Core Configuration的基礎實現。將File擴展獨立於外部,體驗了.NET Core的模塊化設計。

FileConfigurationSource

Configuration.FileExtensions組件中,FileConfigurationSource是繼承於IConfigurationSource的一個抽象類,包含了一個IConfigurationProvider類型的抽象方法,如下所示

   1:  /// <summary>
   2:  /// Builds the <see cref="IConfigurationProvider"/> for this source.
   3:  /// </summary>
   4:  /// <param name="builder">The <see cref="IConfigurationBuilder"/>.</param>
   5:  /// <returns>A <see cref="IConfigurationProvider"/></returns>
   6:  public abstract IConfigurationProvider Build(IConfigurationBuilder builder);

該抽象類中還包括了幾個比較重要的參數,分別用於配置性行為、文件內容訪問以及異常處理。

string Path:文件的路徑

bool Optional:標識載入的文件是否是可選的

bool ReloadOnChange:如果文件發生修改,是否重新載入配置源

int ReloadDelay:載入延遲,單位是毫秒,預設是250毫秒

IFileProvider FileProvider:用於獲取文件內容

Action<FileLoadExceptionContext> OnLoadException:文件載入異常處理

該類對FileProvider有特殊處理,就是如果沒有提供FileProvider實例,則會基於絕對路徑,在最近的現有目錄中創建物理文件提供程式。源碼如下,

   1:  /// <summary>
   2:  /// If no file provider has been set, for absolute Path, this will creates a physical file provider 
   3:  /// for the nearest existing directory.
   4:  /// </summary>
   5:  public void ResolveFileProvider()
   6:  {
   7:      if (FileProvider == null && 
   8:          !string.IsNullOrEmpty(Path) &&
   9:          System.IO.Path.IsPathRooted(Path))
  10:      {
  11:      
var directory = System.IO.Path.GetDirectoryName(Path);
  12:          var pathToFile = System.IO.Path.GetFileName(Path);
  13:          while (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
  14:          {
  15:              pathToFile = System.IO.Path.Combine(System.IO.Path.GetFileName(directory), pathToFile);
  16:              directory = System.IO.Path.GetDirectoryName(directory);
  17:          }
  18:          if (Directory.Exists(directory))
  19:          {
  20:              FileProvider = new PhysicalFileProvider(directory);
  21:              Path = pathToFile;
  22:          }
  23:      }
  24:  }

FileConfigurationProvider

該類是繼承於ConfigurationProvider的抽象類,是從文件系統載入配置的基類,同時還繼承了IDisposable,其抽象方法是Load方法,用於從當前的Provider中以Stream方式載入數據

   1:  /// <summary>
   2:  /// Loads this provider's data from a stream.
   3:  /// </summary>
   4:  /// <param name="stream">The stream to read.</param>
   5:  public abstract void Load(Stream stream);

該類還重寫了ConfigurationProvider的Load方法,並對文件載入中的異常做了處理,Data屬性在前文有提到過,此處不再做其他說明。方法源碼如下所示:

   1:  private void Load(bool reload)
   2:  {
   3:      var file = Source.FileProvider?.GetFileInfo(Source.Path);
   4:      if (file == null || !file.Exists)
   5:      {
   6:          if (Source.Optional || reload) // Always optional on reload
   7:          {
   8:              Data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
   9:          }
  10:          else
  11:          {
  12:              var error = new StringBuilder($"The configuration file '{Source.Path}' was not found and is not optional.");
  13:              if (!string.IsNullOrEmpty(file?.PhysicalPath))
  14:              {
  15:                  error.Append($" The physical path is '{file.PhysicalPath}'.");
  16:              }
  17:              HandleException(new FileNotFoundException(error.ToString()));
  18:          }
  19:      }
  20:      else
  21:      {
  22:          // Always create new Data on reload to drop old keys
  23:          if (reload)
  24:          {
  25:              Data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
  26:          }
  27:          using (var stream = file.CreateReadStream())
  28:          {
  29:              try
  30:              {
  31:                  Load(stream);
  32:              }
  33:              catch (Exception e)
  34:              {
  35:                  HandleException(e);
  36:              }
  37:          }
  38:      }
  39:      // REVIEW: Should we raise this in the base as well / instead?,通過註釋,我們可以知道OnReload()方法可能會在新版中發生變化
  40:      OnReload();
  41:  }
  42:   
  43:  /// <summary>
  44:  /// Loads the contents of the file at <see cref="Path"/>.
  45:  /// </summary>
  46:  /// <exception cref="FileNotFoundException">If Optional is <c>false</c> on the source and a
  47:  /// file does not exist at specified Path.</exception>
  48:  public override void Load()
  49:  {
  50:      Load(reload: false);
  51:  }

另外它還有一個特殊方法,就是參數類型為FileConfigurationSource的構造函數,其主要功能是監控文件,併在FileConfigurationSource.ReloadDelay設置的時間里重新載入文件並返回一個IDisposable類型的值,以下是該構造函數的源碼:

   1:  /// <summary>
   2:  /// Initializes a new instance with the specified source.
   3:  /// </summary>
   4:  /// <param name="source">The source settings.</param>
   5:  public FileConfigurationProvider(FileConfigurationSource source)
   6:  {
   7:      if (source == null)
   8:      {
   9:          throw new ArgumentNullException(nameof(source));
  10:      }
  11:      Source = source;
  12:   
  13:      if (Source.ReloadOnChange && Source.FileProvider != null)
  14:      {
  15:          _changeTokenRegistration = ChangeToken.OnChange(
  16:              () => Source.FileProvider.Watch(Source.Path),
  17:              () => {
  18:                  Thread.Sleep(Source.ReloadDelay);
  19:                  Load(reload: true);
  20:              });
  21:      }
  22:  }

FileConfigurationExtensions

該類是一個靜態類,其提供了的多個擴展方法,主要基於

  • IConfigurationBuilder
  • IFileProvider
  • Action<FileLoadExceptionContext>

包括主要用於設置或獲取IFileProvider對象,前文有介紹過,是存儲於字典之中,需要註意的是,在Get的時候如果字典中並不存在IFileProvider對象,則會實例化一個PhysicalFileProvider對象出來,該類位於Microsoft.Extensions.FileProviders.PhysicalFileProvider

   1:  /// <summary>
   2:  /// Sets the default <see cref="IFileProvider"/> to be used for file-based providers.
   3:  /// </summary>
   4:  /// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
   5:  /// <param name="fileProvider">The default file provider instance.</param>
   6:  /// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
   7:  public static IConfigurationBuilder SetFileProvider(this IConfigurationBuilder builder, IFileProvider fileProvider)
   8:  {
   9:      if (builder == null)
  10:      {
  11:          throw new ArgumentNullException(nameof(builder));
  12:      }
  13:   
  14:      builder.Properties[FileProviderKey] = fileProvider ?? throw new ArgumentNullException(nameof(fileProvider));
  15:      return builder;
  16:  }
  17:   
  18:  /// <summary>
  19:  /// Gets the default <see cref="IFileProvider"/> to be used for file-based providers.
  20:  /// </summary>
  21:  /// <param name="builder">The <see cref="IConfigurationBuilder"/>.</param>
  22:  /// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
  23:  public static IFileProvider GetFileProvider(this IConfigurationBuilder builder)
  24:  {
  25:      if (builder == null)
  26:      {
  27:          throw new ArgumentNullException(nameof(builder));
  28:      }
  29:   
  30:      if (builder.Properties.TryGetValue(FileProviderKey, out object provider))
  31:      {
  32:          return provider as IFileProvider;
  33:      }
  34:   
  35:      return new PhysicalFileProvider(AppContext.BaseDirectory ?? string.Empty);
  36:  }

為指定路徑的物理文件設置文件型Provider,該方法同樣基於PhysicalFileProvider,並返回IConfigurationBuilder對象

   1:  /// <summary>
   2:  /// Sets the FileProvider for file-based providers to a PhysicalFileProvider with the base path.
   3:  /// </summary>
   4:  /// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
   5:  /// <param name="basePath">The absolute path of file-based providers.</param>
   6:  /// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
   7:  public static IConfigurationBuilder SetBasePath(this IConfigurationBuilder builder, string basePath)
   8:  {
   9:      if (builder == null)
  10:      {
  11:          throw new ArgumentNullException(nameof(builder));
  12:      }
  13:   
  14:      if (basePath == null)
  15:      {
  16:          throw new ArgumentNullException(nameof(basePath));
  17:      }
  18:   
  19:      return builder.SetFileProvider(new PhysicalFileProvider(basePath));
  20:  }

以及異常處理,可以看到其異常處理也會存放於字典中,如果字典中找不到,就會返回空,這個地方如果直接使用,需要註意空指針問題。

   1:  /// <summary>
   2:  /// Sets a default action to be invoked for file-based providers when an error occurs.
   3:  /// </summary>
   4:  /// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
   5:  /// <param name="handler">The Action to be invoked on a file load exception.</param>
   6:  /// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
   7:  public static IConfigurationBuilder SetFileLoadExceptionHandler(this IConfigurationBuilder builder, Action<FileLoadExceptionContext> handler)
   8:  {
   9:      if (builder == null)
  10:      {
  11:          throw new ArgumentNullException(nameof(builder));
  12:      }
  13:   
  14:      builder.Properties[FileLoadExceptionHandlerKey] = handler;
  15:      return builder;
  16:  }
  17:   
  18:  /// <summary>
  19:  /// Gets the default <see cref="IFileProvider"/> to be used for file-based providers.
  20:  /// </summary>
  21:  /// <param name="builder">The <see cref="IConfigurationBuilder"/>.</param>
  22:  /// <returns>The <see cref="IConfigurationBuilder"/>.</returns>
  23:  public static Action<FileLoadExceptionContext> GetFileLoadExceptionHandler(this IConfigurationBuilder builder)
  24:  {
  25:      if (builder == null)
  26:      {
  27:          throw new ArgumentNullException(nameof(builder));
  28:      }
  29:   
  30:      if (builder.Properties.TryGetValue(FileLoadExceptionHandlerKey, out object handler))
  31:      {
  32:          return handler as Action<FileLoadExceptionContext>;
  33:      }
  34:      
return null;
  35:  }

該類還有兩個靜態私有變數,指定了文件Provider的Key以及文件載入異常處理Key。

   1:  private static string FileProviderKey = "FileProvider";
   2:  private static string FileLoadExceptionHandlerKey = "FileLoadExceptionHandler";

總結

文件型配置還依賴於.NET Core的其他組件Microsoft.Extensions.FileProviders和Microsoft.Extensions.Primitives。

FileProviders組件提供了文件處理的一般方法,Primitives組件提供了監控機制,同時還包括兩個比較重要的結構體StringValues和StringSegment,本文暫時不做討論,有興趣的朋友,可以自行查看該組件源碼。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • hasNextInt() :判斷是否還有下一個輸入項,其中Xxx可以是Int,Double等。如果需要判斷是否包含下一個字元串,則可以省略Xxx nextInt(): 獲取下一個輸入項。Xxx的含義和上個方法中的Xxx相同,預設情況下,Scanner使用空格,回車等作為分隔符 public stat ...
  • 1. 是否保證線程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保證線程安全; 2. 底層數據結構: Arraylist 底層使用的是Object數組;LinkedList 底層使用的是雙向鏈表數據結構(JDK1.6之前為迴圈鏈表,JDK1.7取消了迴圈。註意雙向鏈表和 ...
  • 1. 前言 對WPF來說ContentControl和 "ItemsControl" 是最重要的兩個控制項。 顧名思義,ItemsControl表示可用於呈現一組Item的控制項。大部分時候我們並不需要自定義ItemsControl,因為WPF提供了一大堆ItemsControl的派生類:Headere ...
  • 在SQL語句查詢過程中,Sqlserver支持使用LEFT()、RIGHT()、SUBSTRING()等幾個函數對字元串進行截取操作,其中Left函數表示從開始字元向後截取多少個字元,Right函數表示從最後位置向前截取多少個字元,SUBSTRING()則可指定截取的起始位置以及截取長度。此文著重介 ...
  • 在C#語言程式開發過程中,很多時候需要對字元串對象的前後空格進行去除,此時就需要使用到Trim()方法來實現這個功能,Trim()方法可以快速去除字元串前端和後端的所有空格。 例如有個字元:string str=" Abc "; 則需要去除字元串前後空格的話,則可以採用:str=str.Trim() ...
  • Dapper優勢和缺點 優點 高性能、易排查、易運維、靈活可控 缺點 和EF相比,手寫sql當修改表結構不易發現bug。 習慣了EF後再來使用Dapper,會很難適應那種沒有了強類型的安全感。不過可以用單元測和心細來避免。 資料庫連接 問題:IDbConnection需不需要手動Open打開連接 答 ...
  • 寫在前面 上一篇文章討論了文件型配置的基本內容,本篇內容討論JSON型配置的實現方式,理解了這一種配置類型的實現方式,那麼其他類型的配置實現方式基本可以觸類旁通。看過了上一篇文章的朋友,應該看得出來似曾相識。此圖主要表達了文件型配置的實現,當然其他配置,包括自定義配置,都會按照這樣的方式去實現。 J... ...
  • 前言: 回顧之前的微信公眾號配置和消息處理的內容,我們已經掌握瞭如何配置伺服器與微信公眾號建立連接,也掌握了通過消息管理的方式,對用戶的信息進行處理,完成公眾號消息回覆功能,實現公眾號與用戶之間的完整對話。而在本文將針對自定義菜單做簡單的開發應用,微信公眾平臺具有自定義菜單的功能。開發者可利用該功能 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...