Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IServiceCollection override a single constructor argument

I have a class that takes three constructor arguments. In my composition root I want to define/override only one of the three constructor arguments; the other two dependencies have already been mapped in my DI container and should get created from the IServiceProvider.

With Ninject I could do something like this:

Bind<IMyInterface>().To<MyClass>()    
    .WithConstructorArgument("constructorArgumentName", x => "constructor argument value");

When Ninject creates MyClass it uses this string parameter and automatically injects the other two dependencies for me. The problem I'm experiencing in .net core is that I cannot tell the IServiceCollection I only want to specify one of the three arguments, I have to define all of them or none. For example, in .net core this is what I have to do:

services.AddTransient<IMyInterface>(x=> new MyClass("constructor argument value", new Dependency2(), new Dependency3());

I don't like having to create new instances of the Dependency2 and Dependency3 classes; these two classes could have their own constructor arguments. I just want the DI to manage those dependencies. So my question is - how do you override a single constructor argument when mapping dependencies in .net core using the IServiceCollection class?

If you can't override just a single contructor argument then how do you resolve a dependency with the IServiceCollection? I tried doing something like this:

services.AddTransient<IMyInterface>(x=> new MyClass("constructor argument value", serviceCollection.Resolve<IDependency2>(), serviceCollection.Resolve(IDependency3>());

But this didn't work, and I couldn't figure out how to resolve dependencies using the IServiceCollection.

like image 739
jwdenny13 Avatar asked Jul 05 '16 16:07

jwdenny13


2 Answers

Try this:

services.AddTransient<IDependency2, Dependency2Impl>();

services.AddTransient<IDependency3, Dependency3Impl>();

services.AddTransient<IMyInterface>(provider=>
    return new MyClass("constructor argument value",
      provider.GetService<IDependency2>(),
      provider.GetService<IDependency3>());
);
like image 123
adem caglin Avatar answered Oct 20 '22 07:10

adem caglin


For anyone who wants a generic but flexible solution: https://gist.github.com/ReallyLiri/c669c60db2109554d5ce47e03613a7a9

The API is

public static void AddSingletonWithConstructorParams<TService, TImplementation>(
            this IServiceCollection services,
            object paramsWithNames
        );
public static void AddSingletonWithConstructorParams(
            this IServiceCollection services,
            Type serviceType,
            Type implementationType,
            object paramsWithNames
        );
public static void AddSingletonWithConstructorParams<TService, TImplementation>(
            this IServiceCollection services,
            params object[] parameters
        );
public static void AddSingletonWithConstructorParams(
            this IServiceCollection services,
            Type serviceType,
            Type implementationType,
            params object[] parameters
        );

Implemented with constructor method reflection.

like image 25
Mugen Avatar answered Oct 20 '22 07:10

Mugen