Preface
In the Core default application template, the configuration file is processed as shown in the following code:
( path: "", optional: true, reloadOnChange: true ); ( path: $"appsettings.{}.json", optional: true, reloadOnChange: true );
Both appsettings.{}.json configuration files are optional and support reloading when the file is modified.
This feature can be used in Core applications to realize that after modifying the configuration file, the modified configuration file does not need to be restarted, and the modified configuration file is automatically loaded, thereby reducing the system downtime. The steps to implement are as follows:
Injection using the configuration API
Suppose you want to inject such a configuration type into the program:
public class WeatherOption { public string City { get; set; } public int RefreshInterval { get; set; } }
The configuration added in :
{ "weather": { "city": "GuangZhou", "refreshInterval": 120 } }
Injection using the configuration API in the ConfigureServices method, the code is as follows:
public void ConfigureServices(IServiceCollection services) { <WeatherOption>(("weather")); (); }
This step is very critical. Through this configuration API, you can associate the injection content with the node where the configuration is located. If you are interested in understanding the underlying implementation, you can continue to view this 。
Content registered in this way supports automatic reloading when the configuration file is modified.
Load the modified configuration in the controller
The life cycle of the controller registered in the dependency injection container of the Core application is Scoped, which means that a new controller instance is created with each request. In this way, you only need to inject the IOptionsSnapshot<TOption> parameter into the controller's constructor, the code is as follows:
[ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { private WeatherOption option; public WeatherForecastController( IOptionsSnapshot<WeatherOption> options ) { = ; } // GET /weatherforcase/options [HttpGet("options")] public ActionResult<WeatherOption> GetOption() { return options; } }
Of course, if you do not want to use this IOptionsSnapshot interface type in the controller (which will bring some refactoring and modification of existing code, and it still has certain risks), you can add injection of WeatherOption in ConfigureServices, and the code is as follows:
public void ConfigureServices(IServiceCollection services) { <WeatherOption>(("weather")); // Add injection to WeatherOption, with the life cycle of Scoped, so that new configuration values can be obtained every request. (serviceProvider => { var snapshot = <IOptionsSnapshot<WeatherOption>>(); return ; }); (); }
In this way, there is no need to inject the IOptionsSnapshot<T> type into the controller. The final controller code is as follows:
[ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { private WeatherOption option; public WeatherForecastController( WeatherOption option ) { = option; } // GET /weatherforcase/options [HttpGet("options")] public ActionResult<WeatherOption> GetOption() { return options; } }
This way, the controller can load the modified new configuration without modifying any code.
Load the modified configuration in Middleware
Middleware (Middleware) is registered in the dependency injection container of the Core application. The life cycle is Singleton, that is, a singleton. Only when the application is started, a global instance is created once when the middleware is created to create a processing connection according to the middleware. Therefore, the modification of the configuration file can only be monitored by injecting IOptionsMonitor<T>. The sample code is as follows:
public class TestMiddleware { private RequestDelegate next; private WeatherOption option; public TestMiddleware( RequestDelegate next, IOptionsMonitor<WeatherOption> monitor ) { = next; option = ; // moni config change (newValue => { option = newValue; }); } public async Task Invoke(HttpContext context) { await ((option)); } }
Of course, in the middleware Task Invoke(HttpContext context) method, it is also possible to directly obtain IOptionsSnapshot<T>, the code is as follows:
public async Task Invoke(HttpContext context) { var snapshot = <IOptionsSnapshot<WeatherOption>>(); await (()); }
However, if you do this, it seems to deviate from the principle of dependency injection, so this practice is not recommended.
Summarize
This is the article about automatically loading new configurations after modifying configuration files in Core. For more related content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!