.NET Core基礎篇之:配置檔案讀取

暢飲無緒發表於2021-11-23

配置檔案是每個專案最基礎的部分,也是不可或缺的部分,比如:資料庫連線、中介軟體屬性等常見的配置。

今天這篇文章主要內容就是,在.Net Core專案中怎樣去讀取配置檔案並使用。

提前準備

appsettings.json 檔案

{
  "User": {
	"userName": "趙一",
	"userAge": 18
  }
}

對應實體模型

public class UserOption
{
	public string userName { get; set; }
	public int userAge { get; set; }
}

常規讀取

1、註冊

在 startup 類中註冊,主要用到的是 Configure 方法:

services.Configure<UserOption>(Configuration.GetSection("User"));
2、控制器中注入並讀取
public class HomeController : ControllerBase
{
    private readonly UserOption user;

    public HomeController(IOptions<UserOption> userOptions)
    {
        user = userOptions.Value;
    }

    [HttpGet]
    public string Get()
    {
        return $"姓名:{user.userName},年齡:{user.userAge} ";
    }
}

輸出結果:姓名:趙一,年齡:18

巢狀讀取

我們對 appsettings.json 檔案做一點小小的改動,增加一個子節點 child

{
  "User": {
	"userName": "趙一",
	"userAge": 18,
	"child": {
	  "userName": "趙一的崽",
	  "userAge": 2
	}
  }
}

再對註冊的程式碼做一點小小的修改:

services.Configure<UserOption>(Configuration.GetSection("User:child"));

輸出結果:姓名:趙一的崽,年齡:2

分例項讀取

這個時候需求又有變化了,需要同時讀取 Userchild 節點的資料,我們試試下面的方法看可行不可行:

// 註冊
services.Configure<UserOption>(Configuration.GetSection("User"));
services.Configure<UserOption>(Configuration.GetSection("User:child"));
// 控制器
public class HomeController : ControllerBase
{
    private readonly UserOption user;
    private readonly UserOption child;

    public HomeController(IOptions<UserOption> userOptions, IOptions<UserOption> childOptions)
    {
        user = userOptions.Value;
        child = childOptions.Value;
    }

    [HttpGet]
    public string Get()
    {
        return $"姓名:{user.userName},年齡:{user.userAge} \r\n姓名:{child.userName},年齡:{child.userAge}";
    }
}

輸出結果很顯然滿足不了我們的需求:

姓名:趙一的崽,年齡:2
姓名:趙一的崽,年齡:2

有的小夥伴肯定會說,在實體模型內在加一個子節點欄位。這樣肯定是沒問題的,但是與常規讀取方式就沒什麼兩樣了。

這裡我要說的是分例項讀取,引入 Configure 的另一個過載方法,與之前不同的是多了一個引數 name

public static IServiceCollection Configure<TOptions>(this IServiceCollection services, string name, IConfiguration config) where TOptions : class;

下面我們重新註冊:

services.Configure<UserOption>("father", Configuration.GetSection("User"));
services.Configure<UserOption>("son", Configuration.GetSection("User:child"));

在控制器建構函式中注入,也引入了一個新的介面物件:IOptionsMonitor

public class HomeController : ControllerBase
{
    private readonly UserOption user;
    private readonly UserOption child;

    public HomeController(IOptionsMonitor<UserOption> userOptions, IOptionsMonitor<UserOption> childOptions)
    {
        user = userOptions.Get("father");
        child = childOptions.Get("son");
    }

    [HttpGet]
    public string Get()
    {
        return $"姓名:{user.userName},年齡:{user.userAge} \r\n姓名:{child.userName},年齡:{child.userAge}";
    }

輸出結果:

姓名:趙一,年齡:18
姓名:趙一的崽,年齡:2

其實還有一個介面物件能實現這樣的效果:IOptionsSnapshot,那 IOptionsMonitorIOptionsSnapshot 有什麼不同呢?請接著往下看。

IOptionsMonitor與IOptionsSnapshot的不同之處

我們先來看看微軟官方的註釋:

IOptionsMonitor

//
// 摘要:
//     Used for notifications when TOptions instances change.
//
// 型別引數:
//   TOptions:
//     The options type.
public interface IOptionsMonitor<out TOptions>
{
    //
    // 摘要:
    //     Returns the current TOptions instance with the Microsoft.Extensions.Options.Options.DefaultName.
    TOptions CurrentValue { get; }

    //
    // 摘要:
    //     Returns a configured TOptions instance with the given name.
    TOptions Get(string name);
    //
    // 摘要:
    //     Registers a listener to be called whenever a named TOptions changes.
    //
    // 引數:
    //   listener:
    //     The action to be invoked when TOptions has changed.
    //
    // 返回結果:
    //     An System.IDisposable which should be disposed to stop listening for changes.
    IDisposable OnChange(Action<TOptions, string> listener);
}

IOptionsSnapshot

//
// 摘要:
//     Used to access the value of TOptions for the lifetime of a request.
//
// 型別引數:
//   TOptions:
//     Options type.
public interface IOptionsSnapshot<out TOptions> : IOptions<TOptions> where TOptions : class, new()
{
    //
    // 摘要:
    //     Returns a configured TOptions instance with the given name.
    TOptions Get(string name);
}

從字面上理解,IOptionsMonitor 建議在配置資訊更改後需要通知的場景下使用,所以多了個 OnChange 的方法;而 IOptionsSnapshot 翻譯過來的意思是:用於在請求的生命週期內訪問配置,有點難以理解哈,我們接下來用程式碼來驗證一下。

IOptionsMonitor 與 IOptionsSnapshot的生命週期

我們對實體模型再做一點小小的修改,增加一個 guid 欄位,並給上預設值:

public class UserOption
{
    public string userName { get; set; }
    public int userAge { get; set; }

    public Guid guid { get; set; } = Guid.NewGuid();
}

我們再次執行程式:

father — 姓名:趙一,年齡:19,編號:e0d71f47-e8f1-4a6d-875e-2074c985f4a0 
son — 姓名:趙一的崽,年齡:3,編號:d865151b-f9bf-4eff-bb4e-8ab6dc61160c

然後不停的重新整理頁面會發現,father 的編號沒有發生任何編號,而 son 的編號每次重新整理都會改變。這是不是比較像我們註冊時所用到的三種模式:

services.AddScoped();
services.AddTransient();
services.AddSingleton()

其中 father 類似 AddSingletonson 則類似 AddScopedAddTransient

大家可以在同一個方法裡多次呼叫 childOptions.Get("son") 看看 son 到底時類似 AddScoped 還是 AddTransient

IOptionsMonitor的OnChange呼叫方式

userOptions.OnChange((user,name)=> { Console.WriteLine(user.userName +"-"+ name); });

無檔案配置

無檔案配置就是不需要以靜態檔案的方式進行配置。相關資訊在配置一次後就不用再做修改,我們可以採用無檔案配置的方式,比如我們熟悉的 AddCors 跨域配置

services.AddCors(op => {
	op.AddPolicy(CorsName, set => {
		set.SetIsOriginAllowed(origin => true).AllowAnyHeader().AllowAnyMethod().AllowCredentials();
            });
        });

我們對之前的註冊方法進行一下改動:

services.Configure<UserOption>(c =>
{
	c.userName = "錢二";
	c.userAge = 60;
});

控制器注入採用常規的注入方式,最終輸出結果:姓名:錢二,年齡:60


以上就是本篇文章的全部內容了,因為時間有限,所以講到的內容比較少,以後時間充裕之後再做相關補充。

分享一個原始碼檢視網站:https://source.dot.net/

相關文章