Dependency injection, inject with parameters

106,671

Solution 1

You can either provide a delegate to manually instantiate your cache provider or directly provide an instance:

services.AddSingleton<ICacheProvider>(provider => new RedisCacheProvider("myPrettyLocalhost:6379"));

services.AddSingleton<ICacheProvider>(new RedisCacheProvider("myPrettyLocalhost:6379"));

Please note that the container will not explicitly dispose of manually instantiated types, even if they implement IDisposable. See the ASP.NET Core doc about Disposal of Services for more info.

Solution 2

If the constructur also has dependencies that should be resolved by DI you can use that:

public class RedisCacheProvider : ICacheProvider
{
    private readonly string _connectionString;
    private readonly IMyInterface _myImplementation;

    public RedisCacheProvider(string connectionString, IMyInterface myImplementation)
    {
        _connectionString = connectionString;
        _myImplementation = myImplementation;
    }
    //interface methods implementation...
}

Startup.cs:

services.AddSingleton<IMyInterface, MyInterface>();
services.AddSingleton<ICacheProvider>(provider => 
    RedisCacheProvider("myPrettyLocalhost:6379", provider.GetService<IMyInterface>()));

Solution 3

You can use :

 services.AddSingleton<ICacheProvider>(x =>
      ActivatorUtilities.CreateInstance<RedisCacheProvider>(x, "myPrettyLocalhost:6379"));

Dependency Injection : ActivatorUtilities will inject any dependencies to your class.

Here is the link to the MS docs: Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance

Also: See @poke's answer here for more information. Basically it pulls from the provided services and any other params you pass, like a composit constructor.

Solution 4

You can use something like the example code below.

Manager class:

public class Manager : IManager
{
    ILogger _logger;
    IFactory _factory;
    public Manager(IFactory factory, ILogger<Manager> logger)
    {
        _logger = logger;
        _factory = factory;
    }
}

Startup.cs class:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IFactory, Factory>(sp =>
    {
        var logger = sp.GetRequiredService<ILogger<Factory>>();
        var dbContext = sp.GetRequiredService<MyDBContext>();
        return new Factory(dbContext, logger);
    });
    services.AddTransient<IManager, Manager>(sp =>
    {
        var factory = sp.GetRequiredService<IFactory>();
        var logger = sp.GetRequiredService<ILogger<Manager>>();
        return new Manager(factory, logger);
    });
}

You can read the full example here: DI in Startup.cs in .Net Core

Solution 5

A bit late to the party, but you could DI inject a factory that creates and exposes an instance of your provider class.

Share:
106,671

Related videos on Youtube

Oleksandr Nahirniak
Author by

Oleksandr Nahirniak

Hi, I'm a software engineer and a technology enthusiast. I started programming 10 years ago and have never stopped. And for the past 7 years, I've been working for the largest outsourcing IT companies in Eastern Europe. I'm experienced in leading teams, designing distributed systems, integrating with 3rd party components, and developing tools for other developers. I write articles and speak at meetups and conferences on subjects like microservices and effective delivery of them in my free time. Nice to meet you!

Updated on December 16, 2021

Comments

  • Oleksandr Nahirniak
    Oleksandr Nahirniak over 2 years

    I'm using vNext implementation of DI. How to pass parameters to constructor? For example, i have class:

    public class RedisCacheProvider : ICacheProvider
    {
        private readonly string _connectionString;
    
        public RedisCacheProvider(string connectionString)
        {
            _connectionString = connectionString;
        }
        //interface methods implementation...
    }
    

    And service register:

    services.AddSingleton<ICacheProvider, RedisCacheProvider>();
    

    How to pass parameter to constructor of RedisCacheProvider class? For example for Autofac:

    builder.RegisterType<RedisCacheProvider>()
           .As<ICacheProvider>()
           .WithParameter("connectionString", "myPrettyLocalhost:6379");
    
  • Himalaya Garg
    Himalaya Garg over 5 years
    Simple and Useful
  • raterus
    raterus about 5 years
    Don't forget if your service takes other parameters you have registered, you can pass a reference to your service when it is registered. e.g. if "RedisCacheProvider" also required ISomeService, you'd do this: services.AddSingleton<ICacheProvider>(provider => new RedisCacheProvider("myPrettyLocalhost:6379", provider.GetService<ISomeService>()));
  • Steven
    Steven over 3 years
    @KévinChalet it would be good if you would specify in your answer that "manually instantiated types" is solely about registering types through AddSingleton<T>(T). Types returned from registered delegates (e.g. using AddSingleton<T>(Func<IServiceProvider, T>)) will in fact be disposed of.
  • Ak777
    Ak777 almost 3 years
    How do I go about handling this if I have another implementation of the ICacheProvider?