1. 程式人生 > 程式設計 >ASP.NET Core中修改配置檔案後自動載入新配置的方法詳解

ASP.NET Core中修改配置檔案後自動載入新配置的方法詳解

前言

在 ASP.NET Core 預設的應用程式模板中, 配置檔案的處理如下面的程式碼所示:

config.AddJsonFile(
 path: "appsettings.json",optional: true,reloadOnChange: true
);
config.AddJsonFile(
 path: $"appsettings.{env.EnvironmentName}.json",reloadOnChange: true
);

appsettings.json 和 appsettings.{env.EnvironmentName}.json 兩個配置檔案都是可選的, 並且支援當檔案被修改時能夠重新載入。

可以在 ASP.NET Core 應用中利用這個特性, 實現修改配置檔案之後, 不需要重啟應用, 自動載入修改過的配置檔案, 從而減少系統停機的時間。 實現的步驟如下:

使用配置 API 進行注入

假設要在程式中注入這樣一個配置型別:

public class WeatherOption {
 public string City { get; set; }
 public int RefreshInterval { get; set; }
}

在 appsettings.json 中新增的配置如下:

{
 "weather": {
 "city": "GuangZhou","refreshInterval": 120
 }
}

在 Startup.cs 的 ConfigureServices 方法中使用配置 API 進行注入, 程式碼如下:

public void ConfigureServices(IServiceCollection services) {
 services.Configure<WeatherOption>(Configuration.GetSection("weather"));
 services.AddControllers();
}

這個步驟很關鍵, 通過這個配置 API 可以把注入內容和配置所在的節點關聯起來。 如果有興趣瞭解底層實現的話, 可以繼續檢視這個 OptionsConfigurationServiceCollectionExtensions.cs 。

通過這種方式註冊的內容, 都是支援當配置檔案被修改時, 自動重新載入的。

在控制器 (Controller) 中載入修改過後的配置

控制器 (Controller) 在 ASP.NET Core 應用的依賴注入容器中註冊的生命週期是 Scoped , 即每次請求都會建立新的控制器例項。 這樣只需要在控制器的建構函式中注入 IOptionsSnapshot<TOption> 引數即可, 程式碼如下:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase {

 private WeatherOption option;

 public WeatherForecastController(
 IOptionsSnapshot<WeatherOption> options
 ) {
 this.option = options.Value;
 }

 // GET /weatherforcase/options
 [HttpGet("options")]
 public ActionResult<WeatherOption> GetOption() {
 return options;
 }
}

當然, 如果不希望在控制器中使用這個 IOptionsSnapshot 介面型別(會帶來一些對現有程式碼重構和修改, 還是有一定的風險的), 可以在 ConfigureServices 中新增對 WeatherOption 的注入, 程式碼如下:

public void ConfigureServices(IServiceCollection services) {
 services.Configure<WeatherOption>(Configuration.GetSection("weather"));
 // 新增對 WeatherOption 的注入, 生命週期為 Scoped , 這樣每次請求都可以獲取新的配置值。
 services.AddScoped(serviceProvider => {
 var snapshot = serviceProvider.GetService<IOptionsSnapshot<WeatherOption>>();
 return snapshot.Value;
 });
 services.AddControllers();
}

這樣在控制器中就不需要注入 IOptionsSnapshot<T> 型別了, 最終控制器的程式碼如下:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase {

 private WeatherOption option;

 public WeatherForecastController(
 WeatherOption option
 ) {
 this.option = option;
 }

 // GET /weatherforcase/options
 [HttpGet("options")]
 public ActionResult<WeatherOption> GetOption() {
 return options;
 }
}

這樣控制器就無需修改任何程式碼即可載入修改過後的新配置。

在中介軟體 (Middleware) 中載入修改過後的配置

中介軟體 (Middleware) 在 ASP.NET Core 應用的依賴注入容器中註冊的生命週期是 Singleton , 即單例的, 只有在當應用啟動時, 根據中介軟體建立處理連時建立一次全域性例項, 所以只能通過注入 IOptionsMonitor<T> 來監聽配置檔案的修改情況, 示例程式碼如下:

public class TestMiddleware {

 private RequestDelegate next;
 private WeatherOption option;

 public TestMiddleware(
 RequestDelegate next,IOptionsMonitor<WeatherOption> monitor
 ) {
 this.next = next;
 option = monitor.CurrentValue;
 // moni config change
 monitor.OnChange(newValue => {
  option = newValue;
 });
 }

 public async Task Invoke(HttpContext context) {
 await context.Response.WriteAsync(JsonSerializer.Serialize(option));
 }

}

當然, 在中介軟體的 Task Invoke(HttpContext context) 方法中, 直接獲取 IOptionsSnapshot<T> 也是可以的, 程式碼如下:

public async Task Invoke(HttpContext context) {
 var snapshot = context.RequestServices.GetService<IOptionsSnapshot<WeatherOption>>();
 await context.Response.WriteAsync(JsonSerializer.Serialize(snapshot.Value));
}

但是這麼做的話, 似乎就偏離了依賴注入的原則了, 因此不推薦這種做法。

總結

到此這篇關於ASP.NET Core中修改配置檔案後自動載入新配置的文章就介紹到這了,更多相關ASP.NET Core自動載入新配置內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!