.NET Core dependency injection -> Get all implementations of an interface
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.
Related videos on Youtube
Nik
Updated on September 16, 2022Comments
-
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 almost 6 yearsAre 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 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 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 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 about 2 yearsNote that this works fine with AddSingleton as well.
-
solublefish about 2 yearsDon't omit the interface type (e.g. services.AddTransient<Rule1>(); services.AddTransient<Rule2>(); )