带有IOptionsSnapshot的ASP.NET核心配置reloadOnChange仍然没有响应

Ray*_*Ray 10 configuration asp.net-core-mvc asp.net-core

我正在使用ASP.NET Core 2.0,我在Main方法中有这样的配置代码:

public static void Main(string[] args)
{
    var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
    var configuration = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .AddJsonFile($"appsettings.{environment ?? "Production"}.json", optional: true, reloadOnChange: true)
        .AddEnvironmentVariables()
        .AddCommandLine(args)
        .Build();
}
Run Code Online (Sandbox Code Playgroud)

我将reloadOnChange设置为true,并在我的控制器中使用IOptionsSnapshot

public HomeController(ILogger<HomeController> logger, IOptionsSnapshot<AppSettings> options)
Run Code Online (Sandbox Code Playgroud)

但是当我修改我的值时appsettings.json,我必须每次都重新启动我的应用程序,或者只是通过刷新浏览器来获取更改.我究竟做错了什么?我试图用控制台和IIS Express运行应用程序; 我也尝试过IOptionsMonitor,同样的事情.顺便问一下,IOptionsMonitor和之间的区别是IOptionsSnapshot什么?

pok*_*oke 34

正如所提到的文件,只需启用reloadOnChange,然后注入IOptionsSnapshot<T>,而不是IOptions<T>就足够了.这要求您正确配置该类型T.通常,配置注册将如下所示:

services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
Run Code Online (Sandbox Code Playgroud)

但是,仔细查看代码,您似乎并没有使用新的ASP.NET Core 2.0配置程序的方式.现在的配置是依赖注入的一部分,所以你将其设置为的一部分WebHostBuilder,使用ConfigureAppConfiguration.例如,这可能是这样的:

public static IWebHost BuildWebHost()
    => new WebHostBuilder()
        .UseKestrel()
        .UseContentRoot(Directory.GetCurrentDirectory())
        .ConfigureAppConfiguration((builderContext, config) =>
        {
            IHostingEnvironment env = builderContext.HostingEnvironment;

            config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
            config.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
        })
        .UseStartup<Startup>()
        .Build();
Run Code Online (Sandbox Code Playgroud)

如果您正在使用默认构建器WebHost.CreateDefaultBuilder(),那么您甚至不需要这样做,因为配置随后会自动设置为reloadOnChange激活后的配置.


IOptionsSnapshot和之间的区别在于,IOptionsMonitorIOptionsSnapshot只是为您提供构造对象时选项的快照IOptionsSnapshot<T>.

这就是使用与以下内容完全相同的原因IOptions<T>:您将它注入构造函数中,然后将其存储options.Value在实例中以便稍后访问这些选项.那时,该对象是固定的,永远不会改变.它只是IOptionsSnapshot<T>被注册为作用域依赖项而不是单例依赖项IOptions<T>,因此它有机会在每个请求上获取当前配置值而不是一次.

IOptionsMonitor<T>然是一个单独的服务,让您检索在任何给定时间的当前配置值.因此,对于需要在需要时获取当前配置的单例服务尤其有用.此外,选项监视器还提供了一种推送机制,以通过配置源通知配置更改.这样,您就可以显式处理配置更改.

选项快照旨在用于瞬态或作用域依赖项,因此您可以在大多数情况下使用它们.只有在极少数情况下,你必须使用一个单独的服务,需要有最新的配置,你应该有必要使用选项显示器.在这些情况下,请注意仅从快照切换到监视器是不够的.通常,您必须以某种方式处理更改的配置(例如清理状态,清除缓存等).因此,您应该始终考虑是否确实需要为所有内容重新加载配置,或者只是重新启动应用程序不是一个可行的选择.

  • @fanray是的,不幸的是,中间件是另一回事.当应用程序运行并执行`Startup.Configure`方法时,中间件设置**.因此,当时解决了所有依赖关系,并将中间件实例作为共享实例保留.所以你不能在那里注入选项.您必须解决`Invoke`方法中的选项,例如使用`context.RequestServices.GetRequiredService <IOptionsSnapshot <AppSettings >>()`. (2认同)