在IServiceCollection扩展中获取服务

and*_*lzo 1 c# dependency-injection asp.net-core asp.net-core-2.0

我有这个扩展名

public static class ServiceCollectionExtensions
{
    public static IServiceCollection MyExtension(this IServiceCollection serviceCollection)
    {
      ...
    }
}
Run Code Online (Sandbox Code Playgroud)

我需要从这样的服务获取信息:

services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
    {
        var myService = <<HERE>>();
        options.TokenValidationParameters = this.GetTokenValidationParameters(myService);
    });
Run Code Online (Sandbox Code Playgroud)

我怎样才能做到这一点?

我尝试获取ServiceProvider之后的邮件var serviceProvider = services.BuildServiceProvider();,然后发送serviceProvider,但这不起作用。

pok*_*oke 5

在您致电时services.AddSomething(),尚未从服务集合构建服务提供商。因此,您当时无法实例化服务。幸运的是,有一种在使用依赖项注入时配置服务的方法。

当您这样做时services.AddSomething(options => …),通常会在服务集合中注册一定数量的服务。然后,还将以特殊方式注册所传递的配置操作,以便稍后实例化该服务时,它将能够执行该配置操作以应用配置。

为此,您需要实现IConfigureOptions<TOptions>(或实际上IConfigureNamedOptions<TOptions>用于身份验证选项)并将其注册为单例。为了您的目的,这可能看起来像这样:

public class ConfigureJwtBearerOptions : IConfigureNamedOptions<JwtBearerOptions>
{
    private readonly IMyService _myService;

    public ConfigureJwtBearerOptions(IMyService myService)
    {
        // ConfigureJwtBearerOptionsis constructed from DI, so we can inject anything here
        _myService = myService;
    }

    public void Configure(string name, JwtBearerOptions options)
    {
        // check that we are currently configuring the options for the correct scheme
        if (name == JwtBearerDefaults.AuthenticationScheme)
        {
            options.TokenValidationParameters = myService.GetTokenValidationParameters();
        }
    }

    public void Configure(JwtBearerOptions options)
    {
        // default case: no scheme name was specified
        Configure(string.Empty, options);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在您的中注册该类型Startup

services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    // add JwtBearer but no need to pass options here
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, configureOptions: null);

// instead we are registering our configuration type to configure it later
services.AddSingleton<IConfigureOptions<JwtBearerOptions>, ConfigureJwtBearerOptions>();
Run Code Online (Sandbox Code Playgroud)

实际上,这只是您刚做完services.AddJwtBearer(scheme, options => { … })就被抽象出来时发生的完全相同的事情,因此您无需关心它。但是,通过手动执行此操作,您现在可以拥有更多功能并可以访问完整的依赖项注入服务提供者。

  • 在 core 2.2 中,我必须将 `IConfigureNamedOptions` 更改为 `IConfigureOptions` (2认同)