6

I want to know if it is possible using build in dotnet core DI framework to register multiple instances of the same class

For example I have a class ToDo that sends off messages to clients. I want 2 instances of the same ToDo object with different injected configuration objects. So at the end I will have 2 separate instances of ToDo object.

Is this possible?


Edit:

Suppose I have a pattern pub/sub

I have a generic class called MessageSubService.cs and the implementation looks something like this

public class ASBMessageSubService : ASBSubService, IASBSubService
{
       public ASBMessageSubService(..., IOptions<ASBSubOptions> options): base(options)
}

So based on this I have multiple ASBMessageSubService that I will need to create. The only thing will differ is the IOptions that passed in. IOptions is internal access. I can not access that property if I use provider.GetRequireServices<T>.

I do understand I can do this

service.AddSingleton<ASBMessageSubService, IASBSubService>
service.AddSingleton<ASBMessageSubService, IASBSubService>
service.AddSingleton<ASBMessageSubService, IASBSubService>

This will register me 3 different instances. The issue is The implementation is that same and I will not be able to resolve it by the type where `nameof(ASBMessageSubService);

I can also register a deligate where I can resolve it based on name or type but this runs into same issue I described above, the type of implementation will be the same.

(I am aware that I can use libraries like structuremap or autofac to get this done with registering them as named instance. However I would like to avoid 3rd party tools like this in this project. )

Any suggestions on this?

Thank you!

2
  • 2
    You call services.AddSingleton<IMyService>(...) multiple times and your consumer classes can take an IEnumerable<IMyService> for example. Commented Jun 8, 2021 at 21:30
  • @DavidG Thank you. I am aware of this approach. However, My services are singletons and what I am confused from this example is that once I inject IEnumnerable<> How will I know what instance to get, since the underneath implementations is that same? For example I will register same ToDoService multiple times per IToDo interface. ? Commented Jun 9, 2021 at 0:11

2 Answers 2

2

David G answered it. I'll expand it slightly to help you and others.

You can register multiple classes, either as themselves, or as an interface:

e.g.

services.AddTransient<Todo>(provider => new Todo(configuration1));
services.AddTransient<Todo>(provider => new Todo(configuration2));
services.AddTransient<Todo>(provider => new Todo(configuration3));
...
services.AddTransient<ITodoWorker, NeedTodos>();

And then for dependency injection take a dependency on IEnumerable<Todo>:

public class NeedTodos : ITodoWorker
{
    public NeedTodos(IEnumerable<Todo> todos)
    {
        foreach (var todo in todos)
        {
            if (todo.Id == "configuration1")
            {
                // an idea if you need to find a specific Todo instance
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

If you need more elaborate DI, definitely check out Scrutor (github.com/khellang/Scrutor)
Thank you, the issue with this solution is that todo.Id will not be accessible since it will be provided by DI as well and will be private readonly at each implementation. I think what I will need is a NamedInstance to be able to resolve services by name
Chipping it too late, but in case it helps anyone. In this case (and I believe this was the intention of the original poster) Id is a public prop of 'Todo'. Or if you use an interface, then Todo would implement that property. Id would then be available to the consuming code.
Update the question.
1

.NET now has keyed services:

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-9.0#keyed-services

.e.g

builder.Services.AddKeyedSingleton<ICache, BigCache>("big");
builder.Services.AddKeyedSingleton<ICache, SmallCache>("small");

var app = builder.Build();

app.MapGet("/big", ([FromKeyedServices("big")] ICache bigCache) => ... 
app.MapGet("/small", ([FromKeyedServices("small")] ICache smallCache) => ...
                                                               

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.