4

I am using StackExchange.Redis to connect to Redis server from .NET Core. How can I inject singleton IConnectionMultiplexer to another singleton service?

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddSingleton<IConnectionMultiplexer>(ConnectionMultiplexer.Connect(GetRedisConnectionString()));
    services.AddSingleton<IMyService>(new MyService(new DbContext(optionsBuilder.Options)), ???);
    ...
}

MyService.cs

private DbContext _dbContext;
private IConnectionMultiplexer _redis;

public MyService(DbContext dbContext, IConnectionMultiplexer redis)
{
    _dbContext = fitDBContext;
    _redis = redis;
}

What do I need to put instead of ??? in ConfigureServices? Is there any other approach?

StackExchange.Redis suggests (link) that we save the returned value of ConnectionMultiplexer.Connect(...) call and reuse it. Therefore, I created singleton service for it (it is based on another StackOverFlow question) which can be injected, but I am not having any luck injecting it to another SINGLETON service MyService.

Sam Carlson
  • 1,891
  • 1
  • 17
  • 44
  • use the factory delegate – Nkosi Jun 07 '19 at 11:05
  • @Nkosi Can you provide an example? – Sam Carlson Jun 07 '19 at 11:06
  • 2
    You will run into problems having the dbcontext as a singleton for `IMyService`! Please see this post https://stackoverflow.com/questions/48767910/entity-framework-core-a-second-operation-started-on-this-context-before-a-previ/48783504#48783504 – alsami Jun 07 '19 at 11:13
  • @Mark alsami is correct in their observation about using the DbContext in the singleton. There are potential issues there.Have you considered making your service scoped? And also letting the service container manage the lifetime of the context – Nkosi Jun 07 '19 at 11:18
  • This might be an [XY problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – Nkosi Jun 07 '19 at 11:19
  • 1
    Technically, only the `IConnectionMultiplexer` needs to be a singleton. `IMyService` doesn't have to be. The container will hold on to the instance. – Nkosi Jun 07 '19 at 11:22

1 Answers1

9

You can use the factory delegate overload for AddSingleton when registering the service

public void ConfigureServices(IServiceCollection services) {

    //...

    services.AddSingleton<IConnectionMultiplexer>(ConnectionMultiplexer.Connect(GetRedisConnectionString()));
    services.AddSingleton<IMyService>(serviceProvider => 
        new MyService(new DbContext(optionsBuilder.Options), serviceProvider.GetRequiredService<IConnectionMultiplexer>())
    );

    //...
}

The delegate passes in an IServiceProvider which can be used to resolve desired services.

Nkosi
  • 235,767
  • 35
  • 427
  • 472