3

I have a WebApi that needs to add a singleton for DI during Setup. But I need to instantiate it during Startup. All of the example code I've found online shows something like this:

services.AddSingleton(new MyService());

This is great, but what do you do if MyService() takes arguments that are setup in DI? For instance, if my service's constructor is like this:

public MyService(ILogger<MyService> logger, IConfiguration config)

There must be a way to instantiate the object when adding it to the DI services, but I'm at a loss.

I'm using .NET 6.

Thanks

Brad Y.
  • 161
  • 2
  • 14
  • Slightly related: https://stackoverflow.com/questions/45924027/avoiding-all-di-antipatterns-for-types-requiring-asynchronous-initialization. It talks about doing startup initialization in the context of DI (icw async). – Steven Jun 20 '22 at 20:50

2 Answers2

2

You basically have two options:

  1. Create the object -with its dependencies- before or during the registration process. With ASP.NET Core the typical place to do this is inside the Startup.ConfigureServices method (or before).
  2. Register it normally and resolve it directly after the container was constructed. In ASP.NET Core this typically means inside the Configure method.

In case the object needs to be available before registration (for instance because the registrations depend on the outcome of a method call on that object), it's important to keep that object as slim and with as little dependencies as possible. Such object, for instance, might have more functionality and dependencies than needs to execute at that moment. In that case it's good to split the object into smaller pieces, such that you only have to compose the least amount of dependencies to get the logic executed.

For instance, instead of injecting an IConfiguration, think about injecting just the parts of the configuration that the object requires. Also think about whether you require logging at this point. Especially logging is tricky, because it's tightly coupled into the DI infrastructure, which makes it more difficult to construct such class manually. This could hold for other framework dependencies as well, because most framework dependencies are registered in the built-in configuration system.

For application components, on the other hand, it should typically fairly easy to compose them before hand. You would usually see that the kinds of services you need this early in the process tend to have little dependencies -or- they can be refactored as such.

If that 'startup' service requires a deeper object graph resolving it from the DI container makes the most sense, but again, that requires the DI Container to be built. Only when executing the Configure method (or later) do you have access to the container.

Steven
  • 166,672
  • 24
  • 332
  • 435
  • 2
    This is great! I was trying to find something like this online and I just couldn't find it. I went with option 2 and it worked well. I do have logging and configuration as params, so I think I'll see if I can do what you recommended at that point. You did a great job of explaining it and laying out all the gotchas. Thanks a lot for this! – Brad Y. Jun 20 '22 at 17:55
-1

What I would suggest is the have the following call in the startup:

builder.Services.AddSingleton<IMyService, MyService>(); Then the DI will instantiate any objects that are required in the MyService constructor.

Hope this helps.

cITsecure
  • 147
  • 6
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 20 '22 at 21:03