.NET Core dependency injection -> Get all implementations of an interface

13,216

Solution 1

It's just a matter of registering all IRule implementations one by one; the Microsoft.Extensions.DependencyInjection (MS.DI) library can resolve it as an IEnumerable<T>. For instance:

services.AddTransient<IRule, Rule1>();
services.AddTransient<IRule, Rule2>();
services.AddTransient<IRule, Rule3>();
services.AddTransient<IRule, Rule4>();

Consumer:

public sealed class Consumer
{
    private readonly IEnumerable<IRule> rules;

    public Consumer(IEnumerable<IRule> rules)
    {
        this.rules = rules;
    }
}

NOTE: The only collection type that MS.DI supports is IEnumerable<T>.

Solution 2

For anyone else looking for an answer. You could also go through your assembly and register all classes that implement a specific interface:

// Get all implementations of IRule and add them to the DI
var rules = typeof(Program).Assembly.GetTypes()
    .Where(x => !x.IsAbstract && x.IsClass && x.GetInterface(nameof(IRule)) == typeof(IRule));

foreach (var rule in rules)
{
    services.Add(new ServiceDescriptor(typeof(IRule), rule, ServiceLifetime.Transient));
    // Replace Transient with whatever lifetime you need
}

This will also provide an IEnumerable<IRule> to every class that is part of your dependency injection. The advantage of this solution is that you do not need to add every single rule to your dependency injection. You can simply add a new implementation of IRule to your project and it will be registered automatically.

Share:
13,216

Related videos on Youtube

Nik
Author by

Nik

Updated on September 16, 2022

Comments

  • Nik
    Nik over 1 year

    I have a interface called IRule and multiple classes that implement this interface. I want to uses the .NET Core dependency injection Container to load all implementation of IRule, so all implemented rules.

    Unfortunately I can't make this work. I know I can inject an IEnumerable<IRule> into my ctor of the controller, but I don't know how to register this setup in the Startup.cs

  • Whoever
    Whoever almost 6 years
    Are there any performance concern resolving IEnumerable<T>? Like a dozen of them, comparing to inject an abstract factory then resolve individual service by name. Thanks
  • Steven
    Steven almost 6 years
    @whoever: this is an impossible to answer question. You will have to measure this for yourself to determine whether or not the performance characteristics are okay in your particular environment. Measure, measure, measure.
  • Whoever
    Whoever almost 6 years
    @Steven Thanks. I just took another look. Indeed, even the two cases I have are different. In one, I loop through and call all implementations, so inject IEnumerable makes perfect sense; In the other, each caller only needs one particular implementation, but there are only two of them and init cost is negligible, kind of a wash. So I decide the save the abstraction for another day ^_^
  • DotnetShadow
    DotnetShadow over 5 years
    @steven How would you go about ordering the rules? Say i have rule1, rule2 and rule3. If you want the order as rule3, rule1, rule2. Perhaps in another section you want rule2 followed by rule1. One way i was thinking was to have a comma delimited list them loop the array and match against the rule name but it seems hacky. Any suggestions?
  • solublefish
    solublefish about 2 years
    Note that this works fine with AddSingleton as well.
  • solublefish
    solublefish about 2 years
    Don't omit the interface type (e.g. services.AddTransient<Rule1>(); services.AddTransient<Rule2>(); )