在 IServiceCollection 扩展中获取服务
Get a service in a IServiceCollection extension
我有这个扩展
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);
});
我该怎么做?
我试图在 var serviceProvider = services.BuildServiceProvider();
之后获取 ServiceProvider
,然后发送 serviceProvider
,但这不起作用..
在您调用 services.AddSomething()
时,服务 provider 尚未从服务集合中构建。所以你不能在那个时候实例化一个服务。幸运的是,有一种方法可以在使用依赖注入的同时配置服务。
当您执行 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 => { … })
时发生的事情完全相同,只是被抽象掉了,因此您无需关心它。但是通过手动执行,您现在拥有更多的权力和访问完整的依赖注入服务提供商。
我有这个扩展
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);
});
我该怎么做?
我试图在 var serviceProvider = services.BuildServiceProvider();
之后获取 ServiceProvider
,然后发送 serviceProvider
,但这不起作用..
在您调用 services.AddSomething()
时,服务 provider 尚未从服务集合中构建。所以你不能在那个时候实例化一个服务。幸运的是,有一种方法可以在使用依赖注入的同时配置服务。
当您执行 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 => { … })
时发生的事情完全相同,只是被抽象掉了,因此您无需关心它。但是通过手动执行,您现在拥有更多的权力和访问完整的依赖注入服务提供商。