在IServiceCollection扩展中获取服务

时间:2017-10-26 19:57:50

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

我有这个扩展名

public static class ServiceCollectionExtensions
{
    public static IServiceCollection MyExtension(this IServiceCollection serviceCollection)
    {
      ...
    }
}

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

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

我该怎么做?

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

1 个答案:

答案 0 :(得分:4)

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

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

为此,您需要实现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);
    }
}

然后在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>();

这实际上就是你刚刚做services.AddJwtBearer(scheme, options => { … })时发生的事情,只是抽象出来,所以你不需要关心它。但通过手动操作,您现在可以获得更多功能并可以访问完整的依赖注入服务提供程序。