Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I have this extension

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

and I need to get information from a service like this:

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

how can I do that?

I tried to get the ServiceProvider after var serviceProvider = services.BuildServiceProvider(); and then I send the serviceProvider, but this doesn't work..

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
223 views
Welcome To Ask or Share your Answers For Others

1 Answer

At the time you are calling services.AddSomething(), the service provider has not been built from the service collection yet. So you cannot instantiate a service at that time. Fortunately, there is a way to configure services while using dependency injection.

When you do services.AddSomething(options => …) what usually happens is that a certain amount of services will be registered with the service collection. And then the passed configuration action will also be registered in a special way, so that when the service is later instantiated, it will be able to execute that configuration action in order to apply the configuration.

For that, you need to implement IConfigureOptions<TOptions> (or actually IConfigureNamedOptions<TOptions> for authentication options) and register it as a singleton. For your purpose, this could look like this:

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);
    }
}

You then register that type in your 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>();

This is actually the exact same thing that happens when you just do services.AddJwtBearer(scheme, options => { … }), just abstracted away, so you don’t need to care about it. But by doing it manually, you now have more power and access to the full dependency injection service provider.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...