【问题标题】:How can I dynamically re-configure a Service during runtime in ASP.NET Core 5?如何在 ASP.NET Core 5 运行时动态重新配置服务?
【发布时间】:2021-06-21 18:06:59
【问题描述】:

我在我的网络应用程序中使用 Google 身份验证,并且 OAuth 密钥当前在 ConfigureServices 中硬编码:

services.AddAuthentication()
    .AddGoogle(options =>
    {
        options.ClientId = "my-client-id";
        options.ClientSecret = "my-client-secret";
    });

但是,我想让站点管理员有机会从 Web 应用程序的设置页面更改 ClientId 和 ClientSecret,最好不必重新启动服务器。

为此,当用户在设置页面上点击“保存”时,我必须以某种方式触发 Google 服务和 GoogleOptions 对象的重新配置。这就是我遇到的麻烦。另外,我想将这些设置存储在 EF Core DbContext 中,而不是物理配置文件中。

到目前为止,我已尝试将设置移动到实现 IPostConfigureOptions 的单独类中。这应该允许我注入我的数据库上下文,因为根据文档, PostConfigure 应该在所有其他配置发生后运行。设置已从这个新类正确加载,但数据库上下文的注入失败,并出现以下异常:

System.InvalidOperationException: Cannot consume scoped service 'AppDatabase' from singleton 'IOptionsMonitor`1[GoogleOptions]'

这很奇怪,因为 ConfigureGoogleOptions 注册为 Scoped,而不是 Singleton。

这是我的选项类:

public class ConfigureGoogleOptions : IPostConfigureOptions<GoogleOptions>
{
    private readonly AppDatabase database;

    public ConfigureGoogleOptions(AppDatabase database)
    {
        this.database = database;
    }
    
    public void PostConfigure(string name, GoogleOptions options)
    {
        options.ClientId = "my-client-id.apps.googleusercontent.com";
        options.ClientSecret = "my-client-secret";
    }
}

并在 ConfigureServices 中注册:

services.AddScoped<IPostConfigureOptions<GoogleOptions>, ConfigureGoogleOptions>();

即使数据库注入有效,还有第二个问题。我班级中的PostConfigure 函数仅在应用程序启动后被调用一次,并且再也不会被调用。我假设它将设置缓存在某处,我不知道如何使该缓存无效或禁用,以便我可以动态提供值。

简短摘要/tl;dr:

我想从我自己的数据库中加载 Google OAuth 服务的 ClientId 和 ClientSecret 设置,并且我希望能够在服务器运行时动态更改它们。

【问题讨论】:

    标签: c# entity-framework asp.net-core dependency-injection


    【解决方案1】:

    在内部,google 处理程序将使用IOptionsMonitor&lt;GoogleOptions&gt; 获取GoogleOptions 一次 或直到它重新加载(例如从配置文件绑定选项和保存文件将触发重新加载)。 IOptionsMonitor 内部将使用 IOptionsMonitorCache 并且此缓存被注册为单例。因此,您从IOptionsMonitor&lt;GoogleOptions&gt; 获得的选项实例与AuthenticationHandler&lt;GoogleOptions&gt;.Options 相同(参考),AuthenticationHandler&lt;GoogleOptions&gt;.Options 用于处理程序内部的各种操作。如果使用该选项,即使其他代码也应该正确地从 IOptionsMonitor&lt;GoogleOptions&gt; 获取它。

    所以要在运行时更改选项,就这么简单:

    //inject the IOptionsMonitor<GoogleOptions> into _googleOptionsMonitor;
    var runtimeOptions = _googleOptionsMonitor.Get(GoogleDefaults.AuthenticationScheme);
    //you change properties of runtimeOptions here
    //...
    

    这里的重点是我们需要使用GoogleDefaults.AuthenticationScheme 作为键来获取正确的选项实例。 IOptionsMonitor.CurrentValue 将使用默认键 Options.DefaultName(这是一个空字符串)。

    【讨论】:

    • 谢谢!我没有意识到它是如此简单。我认为MicrosoftAccountOptionsMicrosoftAccountDefaults.AuthenticationScheme 的过程大致相同。
    • @LázárZsolt 是的,它是一样的,Options 属性在基 AuthenticationHandler&lt;TOptions&gt; 中声明。实际上我在这里发现的是通过阅读源代码,它没有在任何地方记录。这种设计看起来不错,短期内不会改变。
    猜你喜欢
    • 2021-08-08
    • 1970-01-01
    • 2016-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-26
    • 2022-01-27
    • 2017-12-27
    相关资源
    最近更新 更多