serge
serge

Reputation: 15239

Inject dependency in the ConfigureServices

In my ASP.Net Core application I need to inject some dependencies (a repository, in my case) in the ConfigureServices method.

The problem is that method does not allow the use of multiple arguments to inject dependencies. What to do instead ?

Here is my code

public void ConfigureServices(IServiceCollection services)
{
    services.AddOptions();

    // ... 
    services.AddSingleton<ITableRepositories, TableClientOperationsService>();

    // Add framework services.
    services.AddOpenIdConnect(options =>
    {
        // options.ClientId = ...
        options.Events = new OpenIdConnectEvents
        {
            OnTicketReceived = async context =>
            {
                var user = (ClaimsIdentity)context.Principal.Identity;
                if (user.IsAuthenticated)
                {
                    // ... 
                    // vvv 
                    // HERE, I need the ITableRepositories repository; 
                    // vvv
                    var myUser = await repository.GetAsync<Connection>(userId);
                    // ... 
                }
                return;
            }
        };
    });
}

How can I inject the dependency here?

EDIT:

Following the Chris idea (bellow), that seem to work:

public class Startup
{
    // private repository, used in ConfigureServices, initialized in Startup
    ITableRepositories repository;

    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
        // ... etc etc
        Configuration = builder.Build();

        // init repository here
        this.repository = new TableClientOperationsService();
    }

Upvotes: 9

Views: 8447

Answers (2)

Nkosi
Nkosi

Reputation: 247551

You can access the service container via the HttpContext.RequestServices of the current context.

public void ConfigureServices(IServiceCollection services) {
    services.AddOptions();

    // ... 
    services.AddSingleton<ITableRepositories, TableClientOperationsService>();

    // Add framework services.
    services.AddOpenIdConnect(options => {
        // options.ClientId = ...
        options.Events = new OpenIdConnectEvents {
            OnTicketReceived = async context => {
                var user = (ClaimsIdentity)context.Principal.Identity;
                if (user.IsAuthenticated) {
                    // ... 

                    // get the ITableRepositories repository
                    var repository = context.HttpContext.RequestServices.GetService<ITableRepositories>();
                    var myUser = await repository.GetAsync<Connection>(userId);

                    // ... 
                }
                return;
            }
        };
    });
}

So technically you don't need access to the dependency within the ConfigureServices as the inline expression could be extracted into its own function.

public void ConfigureServices(IServiceCollection services) {
    services.AddOptions();

    // ... 
    services.AddSingleton<ITableRepositories, TableClientOperationsService>();

    // Add framework services.
    services.AddOpenIdConnect(options => {
        // options.ClientId = ...
        options.Events = new OpenIdConnectEvents {
            OnTicketReceived = TicketReceived
        };
    });
}

private async Task TicketReceived(TicketReceivedContext context) {
    var user = (ClaimsIdentity)context.Principal.Identity;
    if (user.IsAuthenticated) {
        // ... 

        // get the ITableRepositories repository
        var repository = context.HttpContext.RequestServices.GetService<ITableRepositories>();
        var myUser = await repository.GetAsync<Connection>(userId);

        // ... 
    }
    return;
}

Upvotes: 14

Chris Pratt
Chris Pratt

Reputation: 239440

Well, you can't. However, you can utilize the StartUp constructor to set one or more properties that you can utilize inside ConfigureServices. For example:

public StartUp(IHostingEnvironment env)
{
    ...

    FooInstance = new Foo();
}

public IFoo FooInstance { get; }

public void ConfigureServices(IServiceCollection services)
{
    // you can now use `Foo` here, without injecting it.
}

EDIT (based on code added to question)

In this particular scenario, especially since this is a singleton, you can simply create an instance manually and then bind to that instance instead of a generic type. For example:

var repository = new TableClientOperationsService();
services.AddSingleton<ITableRepositories>(repository);

Then, you can simply utilize this variable directly in the code below where you need it:

var myUser = await repository.GetAsync<Connection>(userId);

Upvotes: 1

Related Questions