C
C#•3w ago
Raphael Nunes

Get all services injected as Keyed

I've injected some items using AddKeyedScoped and a on service I need to get all implementations In my mind, it should work
public interface IMyDependency;
public class MyImplementationA : IMyDependency;
public class MyImplementationB : IMyDependency;

// 👇 It's should work 😿
public class MyService(IEnumerable<IMyDependency> dependencies)
{}


public static class DependenciesInject
{
static IServiceCollection AddMys(this IServiceCollection services)
{
services
.AddKeyedScoped<IMyDependency, MyImplementationA>("ImplementationA")
.AddKeyedScoped<IMyDependency, MyImplementationB>("ImplementationB");
}
}
public interface IMyDependency;
public class MyImplementationA : IMyDependency;
public class MyImplementationB : IMyDependency;

// 👇 It's should work 😿
public class MyService(IEnumerable<IMyDependency> dependencies)
{}


public static class DependenciesInject
{
static IServiceCollection AddMys(this IServiceCollection services)
{
services
.AddKeyedScoped<IMyDependency, MyImplementationA>("ImplementationA")
.AddKeyedScoped<IMyDependency, MyImplementationB>("ImplementationB");
}
}
There are some how to get all services that implement IMyDependency?
7 Replies
ste
ste•3w ago
Have you figured out how?
SleepWellPupper
SleepWellPupper•2w ago
Questions: Why did you register the services as keyed? Are you actually resolving keyed services? Did you run this to check if it works (you didn't mention)? Notes: IIRC, calling AddScoped is not idempotent and will actually register multiple implementations of IMyDependency, with the last one to be added being resolved when injecting IMyDependency, and all being resolved when injecting IEnumerable<IMyDependency>.
Raphael Nunes
Raphael NunesOP•2w ago
Let me rephrase that better. Contract and implementations
public interface IMyDependency
{
Task PerformAsync();
}
public class MyImplementationA : IMyDependency
{
public Task PerformAsync(){...}
}
public class MyImplementationB : IMyDependency
{
public Task PerformAsync(){...}
}
public interface IMyDependency
{
Task PerformAsync();
}
public class MyImplementationA : IMyDependency
{
public Task PerformAsync(){...}
}
public class MyImplementationB : IMyDependency
{
public Task PerformAsync(){...}
}
My goal: I want to perform parallel or sequential
public class Dispacher(IServiceBusClient sbClient)
{
public static Task Invoke(bool isSequential)
{
var command = new Object();
if (isSequential)
sbClient.AddAsync("action-sequential", command);
else
{
sbClient.AddAsync("action-a", command);
sbClient.AddAsync("action-b", command);
}
}
}
public class Dispacher(IServiceBusClient sbClient)
{
public static Task Invoke(bool isSequential)
{
var command = new Object();
if (isSequential)
sbClient.AddAsync("action-sequential", command);
else
{
sbClient.AddAsync("action-a", command);
sbClient.AddAsync("action-b", command);
}
}
}
Paralell triggers
public class FuncA([FromKeyedServices("ImplementationA"]IMyDependency dependencies)
{
public static Task Run([ServiceBusTrigger("action-a")] object _) => dependencies.PerformAsync();
}
public class FuncB([FromKeyedServices("ImplementationB"]IMyDependency dependencies)
{
public static Task Run([ServiceBusTrigger("action-b")] object _) => dependencies.PerformAsync();
}
public class FuncA([FromKeyedServices("ImplementationA"]IMyDependency dependencies)
{
public static Task Run([ServiceBusTrigger("action-a")] object _) => dependencies.PerformAsync();
}
public class FuncB([FromKeyedServices("ImplementationB"]IMyDependency dependencies)
{
public static Task Run([ServiceBusTrigger("action-b")] object _) => dependencies.PerformAsync();
}
Sequential triggers
public class FuncSequetial(IEnumerable<IMyDependency> dependencies)
{
public static Task Run([ServiceBusTrigger("action-sequential")] object _) => dependencies.PerformAsync();
{
foreach (var d in dependencies) d.PerformAsync();
}
}
public class FuncSequetial(IEnumerable<IMyDependency> dependencies)
{
public static Task Run([ServiceBusTrigger("action-sequential")] object _) => dependencies.PerformAsync();
{
foreach (var d in dependencies) d.PerformAsync();
}
}
@ste I resolve this way: injecting MyImplementation twice, one using Keyed and another not
public static class DependenciesInject
{
static IServiceCollection AddMys(this IServiceCollection services)
{
services
.AddKeyedScoped<IMyDependency, MyImplementationA>("ImplementationA")
.AddScoped<IMyDependency, MyImplementationA>()

.AddKeyedScoped<IMyDependency, MyImplementationB>("ImplementationB")
.AddScoped<IMyDependency, MyImplementationB>();
}
}
public static class DependenciesInject
{
static IServiceCollection AddMys(this IServiceCollection services)
{
services
.AddKeyedScoped<IMyDependency, MyImplementationA>("ImplementationA")
.AddScoped<IMyDependency, MyImplementationA>()

.AddKeyedScoped<IMyDependency, MyImplementationB>("ImplementationB")
.AddScoped<IMyDependency, MyImplementationB>();
}
}
I think it's bit weird.
cap5lut
cap5lut•2w ago
the DI works im pretty sure u r registering in total 4 scoped services here. so for example if u want to only register 1 instance of MyImplementationA as keyed service and generally for the interface, u would have to provide a factory delegate:
services
.AddKeyedScoped<IMyDependency, MyImplementationA>("ImplementationA")
.AddScoped<IMyDependency, MyImplementationA>(sp => sp.GetRequiredKeyedService<MyImplementationA>("ImplementationA"));
services
.AddKeyedScoped<IMyDependency, MyImplementationA>("ImplementationA")
.AddScoped<IMyDependency, MyImplementationA>(sp => sp.GetRequiredKeyedService<MyImplementationA>("ImplementationA"));
but from the way u describe ur problem, i wouldnt use keyed services at all. i would simply register them as implementation type and as interface:
services
.AddScoped<MyImplementationA>()
.AddScoped<IMyDependency>(sp => sp.GetRequiredService<MyImplementationA>());
services
.AddScoped<MyImplementationA>()
.AddScoped<IMyDependency>(sp => sp.GetRequiredService<MyImplementationA>());
and then
public class FuncA([FromKeyedServices("ImplementationA"]IMyDependency dependencies)
{
public static Task Run([ServiceBusTrigger("action-a")] object _) => dependencies.PerformAsync();
}
public class FuncA([FromKeyedServices("ImplementationA"]IMyDependency dependencies)
{
public static Task Run([ServiceBusTrigger("action-a")] object _) => dependencies.PerformAsync();
}
would simply become
public class FuncA([FromServices] MyImplementationA dependencies)
{
public static Task Run([ServiceBusTrigger("action-a")] object _) => dependencies.PerformAsync();
}
public class FuncA([FromServices] MyImplementationA dependencies)
{
public static Task Run([ServiceBusTrigger("action-a")] object _) => dependencies.PerformAsync();
}
this might be off, because i dont really get what the IServiceBusClient is/does
Raphael Nunes
Raphael NunesOP•2w ago
ServiceBusClient it's a message broker client, used to send items to queue I get it. But it's not testable I've tried to implement a factory
interface IFactory
{
IEnumerable<IMyDependecy> CreateAll();
}
public class Factory([FromKeyedServices("ImplementationA"]IMyDependency dependencyA, [FromKeyedServices("ImplementationB"]IMyDependency dependencyB) : IFactory
{
IEnumerable<IMyDependecy> CreateAll() => [dependencyA,dependencyB]
}
public static class DependenciesInject
{
static IServiceCollection AddMys(this IServiceCollection services)
{
services
.AddScoped<IFactory, Factory>()
.AddKeyedScoped<IMyDependency, MyImplementationA>("ImplementationA")
.AddKeyedScoped<IMyDependency, MyImplementationB>("ImplementationB");
}
}
interface IFactory
{
IEnumerable<IMyDependecy> CreateAll();
}
public class Factory([FromKeyedServices("ImplementationA"]IMyDependency dependencyA, [FromKeyedServices("ImplementationB"]IMyDependency dependencyB) : IFactory
{
IEnumerable<IMyDependecy> CreateAll() => [dependencyA,dependencyB]
}
public static class DependenciesInject
{
static IServiceCollection AddMys(this IServiceCollection services)
{
services
.AddScoped<IFactory, Factory>()
.AddKeyedScoped<IMyDependency, MyImplementationA>("ImplementationA")
.AddKeyedScoped<IMyDependency, MyImplementationB>("ImplementationB");
}
}
But the open-closed principle may kill me 🙂 Because, for each implementation I will need edit my DI config and Factory class
ste
ste•2w ago
Solid isn't real, it cannot hurt you
cap5lut
cap5lut•2w ago
u have to tell DI to use the factory to create the service eg .AddScoped<IMyDependency>(sp => sp.GetRequiredService<Factory>().Create()) DI wont magically use services that are registered just because their names include Factory and as far as i know u cant create multiple services with one call (not to mention that what ur factory does isnt even really doing anything u couldnt do by just injecting IEnumerable<IMyDependency>)

Did you find this page helpful?