4

The code sample below is from Asp.Net Core ConfigureServices method in Startup.cs.

I am first registering a singleton service called AppState. Subsequent to that, I am configuring OpenIdConnect, and inside the OnTokenValidated lambda, I need to access the AppState service that I just registered in the DI container up above.

What is the most elegant way of accessing the AppState service instance?

I would prefer to not call services.BuildServiceProvider() inside the ConfigureServices method if at all possible.

services.AddSingleton<AppState>();

services.Configure<OpenIdConnectOptions>(AzureADB2CDefaults.OpenIdScheme, options =>
{
    options.Events = new OpenIdConnectEvents
    {
        OnTokenValidated = async ctx =>
        {
            //How to get access to instance of AppState, 
            //which was added to DI container up above
            AppState appState = //{get from DI somehow}; 
            appState.DoSomething();
        }
    };
});

EDIT: Using the answer below, I edited the code like so, but I can confirm that the OnTokenValidated event is not firing, as opposed to the code above in my original question, which does fire:

services.AddOptions<OpenIdConnectOptions>(AzureADB2CDefaults.OpenIdScheme)
            .Configure<IServiceScopeFactory>((options, sp) => {
                using (var scope = sp.CreateScope())
                {
                    options.Events = new OpenIdConnectEvents
                    {
                        OnTokenValidated = async ctx =>
                        {
                            var appState = scope.ServiceProvider.GetRequiredService<AppState>();

                            await appState.Dosomething();         
                        }
                    };
                }
            });
1
  • @Nkosi Thanks for your answer...Could you please advise what I might be doing wrong. I have edited my question with the new code, and the OnTokenValidated does not fire. Commented Apr 3, 2020 at 2:00

4 Answers 4

9

Use the TokenValidatedContext to get access to the current request service provider and resolve the service

services
    .Configure<OpenIdConnectOptions>(AzureADB2CDefaults.OpenIdScheme, options => {
        options.Events = new OpenIdConnectEvents {
            OnTokenValidated = async ctx => {
                //Get access to instance of AppState, 
                //which was added to DI container up above
                AppState appState = ctx.HttpContext.RequestServices
                    .GetRequiredService<AppState>();
                await appState.DoSomething();

                //...
            }
        };
    });
Sign up to request clarification or add additional context in comments.

1 Comment

This has helped me get closer to a similar issue, but what I find here is that the OnTokenValidated event seems to only fire if i log into the WebApp from the home page (when using razor) I'm trying to figure out how to get this to fire when the login process is initiated from any protected page or resource.
4

You can access the DI service from the event context:

services.AddSingleton<AppState>();

services.Configure<OpenIdConnectOptions>(AzureADB2CDefaults.OpenIdScheme, options =>
{
    options.Events = new OpenIdConnectEvents
    {
        OnTokenValidated = async ctx =>
        {
            var appState = (AppState)ctx.HttpContext.RequestServices.GetService(typeof(AppState));
            appState.DoSomething();
        }
    };
});

Comments

0

Calling services.Configure<T>, adds an IConfigureOptions<T> to the service container that calls your action method; https://github.com/aspnet/Options/blob/master/src/Microsoft.Extensions.Options/OptionsServiceCollectionExtensions.cs#L72

You can define your own implementation of IConfigureOptions<T> and inject any service you like.

Comments

0

To elegantly access the AppState service within the OnTokenValidated event handler without using BuildServiceProvider(), you can inject the AppState instance directly into the event handler using a scoped factory.

Instead of creating a new scope within the Configure lambda, simply capture the IServiceProvider as a parameter and resolve the AppState service within the OnTokenValidated event handler. Here’s the revised code:

services.AddSingleton<AppState>();

services.Configure<OpenIdConnectOptions>(AzureADB2CDefaults.OpenIdScheme, options =>
{
    options.Events = new OpenIdConnectEvents
    {
        OnTokenValidated = async ctx =>
        {
            var appState = ctx.HttpContext.RequestServices.GetRequiredService<AppState>();
            await appState.DoSomething();
        }
    };
});

Over here ctx.HttpContext.RequestServices provides access to the dependency injection container for the current request.

  • You retrieve the AppState instance from the container without creating an extra service provider or scope.
  • This method is efficient, as it directly accesses the already registered singleton AppState service within the request's DI context.

This keeps the ConfigureServices method clean and avoids manually managing scopes.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.