Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I correctly inject an IHostedService into a Controller? #596

Closed
stijnherreman opened this issue Jul 31, 2018 · 7 comments
Closed
Labels

Comments

@stijnherreman
Copy link

I'm using ASP.NET Core 2.1 and I'm running into the issue described at https://simpleinjector.readthedocs.io/en/latest/disposabletransientcomponent.html

I have a service implementing BackgroundService. It is registered with services.AddSingleton<IHostedService, ActorSystemBackgroundService>(). When trying to add it to the constructor of a controller, e.g. public AutomatedTestsController(ActorSystemBackgroundService actorSystemBackgroundService), I get the following error:

-[Disposable Transient Component] ActorSystemBackgroundService is registered as transient, but implements IDisposable.

I don't understand why it says ActorSystemBackgroundService is registered as transient, I'm registering it as a singleton. How do I correctly resolve the error in this case?

@dotnetjunkie
Copy link
Collaborator

That's because your constructor references ActorSystemBackgroundService instead of IHostedService. Simple Injector tries to cross-wire ActorSystemBackgroundService for you by looking in the IServiceCollection, but it can't find any, because you only registered an IHostedService; this is simply the way the ASP.NET Core DI works.

Because Simple Injector can't find ActorSystemBackgroundService in ASP.NET Core, and since it is a concrete type, Simple Injector will create the type for you. In doing so, however, it creates the type as Transient.

So fix this, you can do 2 things:

  • Change your constructor to reference IHostedService
  • Register ActorSystemBackgroundService as itself, e.g. services.AddSingleton<ActorSystemBackgroundService>().

@stijnherreman
Copy link
Author

Right, it's obvious now that you say it 😄 Thank you!

I've changed the registration as follows, if I understand correctly then the background service must be registered as an IHostedService to work correctly:

services.AddSingleton<ActorSystemBackgroundService>();
services.AddSingleton<IHostedService, ActorSystemBackgroundService>(
	serviceProvider => serviceProvider.GetService<ActorSystemBackgroundService>());

@dotnetjunkie
Copy link
Collaborator

So why does your AutomatedTestsController need to depend on ActorSystemBackgroundService instead of IHostedService?

@stijnherreman
Copy link
Author

There could be multiple IHostedServices and I need a specific one. Or if you mean to ask why ActorSystemBackgroundService instead of IActorSystemBackgroundService, I'm still in the PoC phase so things will probably still change a bit.

Looking at HostedServiceExecutor, I assume registering it as an IHostedService ensures that ASP.NET Core calls the StartAsync and StopAsync methods at the right time, for all IHostedServices.

@dotnetjunkie
Copy link
Collaborator

@stijnherreman
Copy link
Author

I hadn't seen it yet. I did see you talk somewhere else about creating an adapter, but didn't quite understand it. Thanks for the link, I'll see if I can make it fit with my requirements.

@olegkap
Copy link

olegkap commented Aug 10, 2018

Or I would suggest this post https://stackoverflow.com/questions/51254053/how-to-inject-a-reference-to-a-specific-ihostedservice-implementation

I have more than one hosted service and followed that post to inject specific hosted service into controller.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants