I just need to access my BackgroundService from a controller. Since BackgroundServices are injected with
services.AddSingleton<IHostedService, MyBackgroundService>()
How can I use it from a Controller class?
I just need to access my BackgroundService from a controller. Since BackgroundServices are injected with
services.AddSingleton<IHostedService, MyBackgroundService>()
How can I use it from a Controller class?
This is how I solved it:
public interface IHostedServiceAccessor<T> where T : IHostedService
{
T Service { get; }
}
public class HostedServiceAccessor<T> : IHostedServiceAccessor<T>
where T : IHostedService
{
public HostedServiceAccessor(IEnumerable<IHostedService> hostedServices)
{
foreach (var service in hostedServices) {
if (service is T match) {
Service = match;
break;
}
}
}
public T Service { get; }
}
Then in Startup
:
services.AddTransient<IHostedServiceAccessor<MyBackgroundService>, HostedServiceAccessor<MyBackgroundService>>();
And in my class that needs access to the background service...
public class MyClass
{
private readonly MyBackgroundService _service;
public MyClass(IHostedServiceAccessor<MyBackgroundService> accessor)
{
_service = accessor.Service ?? throw new ArgumentNullException(nameof(accessor));
}
}
private readonly Guid _id = Guid.NewGuid();
to the service class and observe it when the service starts vs when obtained via IHostedServiceAccessor, you'll notice it's two different values. –
Siret Transient
but as a Singleton
. The microsoft documentation states that the hosted service must create the scopes by itself, as if you add it as Scoped
, you'll probably use disposed objects. –
Muldon In the end I've injected IEnumerable<IHostedService>
in the controller and filtered by Type:background.FirstOrDefault(w => w.GetType() == typeof(MyBackgroundService)
This is how I solved it:
public interface IHostedServiceAccessor<T> where T : IHostedService
{
T Service { get; }
}
public class HostedServiceAccessor<T> : IHostedServiceAccessor<T>
where T : IHostedService
{
public HostedServiceAccessor(IEnumerable<IHostedService> hostedServices)
{
foreach (var service in hostedServices) {
if (service is T match) {
Service = match;
break;
}
}
}
public T Service { get; }
}
Then in Startup
:
services.AddTransient<IHostedServiceAccessor<MyBackgroundService>, HostedServiceAccessor<MyBackgroundService>>();
And in my class that needs access to the background service...
public class MyClass
{
private readonly MyBackgroundService _service;
public MyClass(IHostedServiceAccessor<MyBackgroundService> accessor)
{
_service = accessor.Service ?? throw new ArgumentNullException(nameof(accessor));
}
}
private readonly Guid _id = Guid.NewGuid();
to the service class and observe it when the service starts vs when obtained via IHostedServiceAccessor, you'll notice it's two different values. –
Siret Transient
but as a Singleton
. The microsoft documentation states that the hosted service must create the scopes by itself, as if you add it as Scoped
, you'll probably use disposed objects. –
Muldon Add BackgroundService in ConfigureServices function:
public void ConfigureServices(IServiceCollection services)
{
services.AddHostedService<ListenerService>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
Inject in the Controller:
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private readonly IHostedService listenerService;
public ValuesController(IHostedService listenerService)
{
this.listenerService = listenerService;
}
}
I used BackgroundService to spin up multiple listeners for AWSSQS Listeners. If consumer wants to spin new listener then it could be done by POSTing to a Controller method (end point).
© 2022 - 2024 — McMap. All rights reserved.
public ControllerName(IHostedService service){ .. }
Did you try to read documentation before asking here? learn.microsoft.com/en-us/aspnet/core/fundamentals/… – PyromancyStart()
invoked on it – Publishing