在ASP.NET Core 2.1中如何从控制器访问BackgroundService

11

我只需要从控制器中访问我的BackgroundService。由于BackgroundServices是通过依赖注入来实现的,

services.AddSingleton<IHostedService, MyBackgroundService>()

我该如何在控制器类中使用它?


1
在控制器中添加构造函数 public ControllerName(IHostedService service){ .. }。在向此处提问之前,您是否尝试阅读文档?https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection - Roman Marusyk
3
是的,我做到了。 我需要在我的控制器中注入BackgroundService,而不是IHostedService接口。我可以有多个BackgroundService,并且所有的都被注入为services.AddSingleton<IHostedService,...>()。 - Alex Troto
2
需要非常小心的是,aspnet将HostedServices注册为瞬态实例。因此,每次您接收到一个实例时,它都不是已调用Start()的实例。 - Chris Marisic
3个回答

9

最终我在控制器中注入了 IEnumerable<IHostedService> 并按类型进行筛选:background.FirstOrDefault(w => w.GetType() == typeof(MyBackgroundService)


4
这是我解决问题的方法:
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; }
}

然后在 Startup 中:

services.AddTransient<IHostedServiceAccessor<MyBackgroundService>, HostedServiceAccessor<MyBackgroundService>>();

在需要访问后台服务的我的类中...

public class MyClass
{
  private readonly MyBackgroundService _service;

  public MyClass(IHostedServiceAccessor<MyBackgroundService> accessor)
  {
    _service = accessor.Service ?? throw new ArgumentNullException(nameof(accessor));
  }
}

警告一句——如果遇到一些不寻常的行为,请注意,虽然IHostedService实现看起来像单例,但其状态将无法访问。例如,如果您在服务类中添加private readonly Guid _id = Guid.NewGuid();并观察它在服务启动时与通过IHostedServiceAccessor获取时的值,您会发现它们是两个不同的值。 - UtopiaLtd
@UtopiaLtd 不要将后台服务添加为“Transient”,而应该添加为“Singleton”。Microsoft文档指出,托管服务必须自己创建作用域,如果您将其添加为“Scoped”,则可能使用已释放的对象。 - Emy Blacksmith
从.NET 5.0开始,API派生自ControllerBase。如果这个答案解决了"MyController"如何从ControllerBase派生并调用BackgroundService的问题,那就更好了。 - H2ONaCl

0
在 ConfigureServices 函数中添加 BackgroundService:
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHostedService<ListenerService>();


        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

在控制器中注入:

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    private readonly IHostedService listenerService;

    public ValuesController(IHostedService listenerService)
    {
        this.listenerService = listenerService;
    }
}

我使用BackgroundService为AWSSQS Listeners启动多个监听器。如果消费者想要启动新的监听器,则可以通过POST到控制器方法(端点)来完成。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接