首页 > 解决方案 > 在没有 BuildServiceProvider() 的情况下在 AddOpenIdConnect 中获取 ServiceProvider

问题描述

有没有一种好方法可以在我们完全设置 DI 容器的地方获取ServiceProviderAddOpenIdConnect配置ClientSecret?(例如在Configure(IApplicationBuilder app)

我们从其他地方获取客户端机密,我们喜欢为此使用 DI。

目前我们这样做,但我真的很想删除 services.BuildServiceProvider()

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddOpenIdConnect(AuthenticationScheme, options =>
    {
        ServiceProvider serviceProvider = services.BuildServiceProvider(); // we like to prevent this
        options.ClientSecret = serviceProvider.GetRequiredService<ISecretRetriever>().GetClientSecret();

笔记

对于像OnValidatePrincipal我们可以从中得到它的事件CookieValidatePrincipalContext.HttpContext.RequestServices

使用services.BuildServiceProvider()会给出这个警告:

警告“从应用程序代码调用‘BuildServiceProvider’会导致创建一个额外的单例服务副本”

标签: c#asp.net-coredependency-injectionopenid-connectasp.net-core-3.1

解决方案


身份验证的配置系统使用选项模式。这意味着以下方法将具有与您的问题中显示的方法类似的效果:

services.AddAuthentication()
    .AddOpenIdConnect(AuthenticationScheme, options =>
    {
        // ...
    });

services.Configure<OpenIdConnectOptions>(AuthenticationScheme, options =>
{
    options.ClientSecret = "ClientSecret";
});

这很有用,因为选项模式支持 DI,使用如下内容:

services.AddOptions<OpenIdConnectOptions>(AuthenticationScheme)
    .Configure<ISecretRetriever>((options, secretRetriever) =>
    {
        options.ClientSecret = secretRetriever.GetClientSecret();
    });

要访问Configure适用于 DI 的方法,您必须首先调用AddOptions. 在此示例中,Configure给定了一个类型参数,它表示所需的依赖项。这将作为第二个参数传递到您的配置回调中,位于OpenIdConnectOptions正在配置的实例之后。


推荐阅读