我正在尝试使用IHostedService创建后台服务。如果我只有一个后台服务,一切都会正常。当我尝试创建多个IHostedService
实现时,只有第一个注册的实现才真正运行。
services.AddSingleton<IHostedService, HostedServiceOne>();
services.AddSingleton<IHostedService, HostedServiceTwo>();
在上面的示例中,StartAsync
上的HostedServiceOne
被调用,而StartAsync
上的HostedServiceTwo
从未被调用。如果我交换注册IHostedService
的两个实现的顺序(将{{1}放在IHostedServiceTwo
之前),则会调用IHostedServiceOne
上的StartAsync
,但不会调用{{1 }}。
编辑:
我被引导至以下位置:
How to register multiple implementations of the same interface in Asp.Net Core?
但这不适用于HostedServiceTwo
。要使用建议的方法,我必须致电HostedServiceOne
,但似乎IHostedService
似乎是在内部被调用。我什至不知道该在哪里触发serviceProvider.GetServices<IService>();
。
答案 0 :(得分:5)
如下注册您的HostedService
:
// services.AddSingleton<IHostedService, HostedServiceOne>();
// services.AddSingleton<IHostedService, HostedServiceTwo>();
services.AddHostedService<HostedServiceOne>();
services.AddHostedService<HostedServiceTwo>();
它将按预期工作。
答案 1 :(得分:2)
我有同样的问题。 必须在每个服务中返回Task.CompletedTask;
public class MyHostedService: IHostedService
{
public Task StartAsync(CancellationToken cancellationToken)
{
Task.Run(() => SomeInfinityProcess(cancellationToken));
return Task.CompletedTask;
}
public void SomeInfinityProcess(CancellationToken cancellationToken)
{
for (; ; )
{
Thread.Sleep(1000);
if (cancellationToken.IsCancellationRequested)
break;
}
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
Startup.cs是相同的:
services.AddHostedService<MyHostedService>();
services.AddHostedService<MyHostedService2>();
...
答案 2 :(得分:1)
答案 3 :(得分:0)
这似乎可以通过decorating IHostedService
来解决,尽管.Net Core的默认IoC容器不支持注册装饰器,但是有一个简单的解决方法。
您可以像这样为IHostedService
创建一个装饰器:
public abstract class MyHostedServiceDecorator : IHostedService
{
private readonly MyHostedServiceDecorator _next;
protected MyHostedServiceDecorator(MyHostedServiceDecorator next)
{
_next = next;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
await StartAsyncInternal(cancellationToken);
if (_next != null)
{
await _next.StartAsync(cancellationToken);
}
}
public async Task StopAsync(CancellationToken cancellationToken)
{
await StopAsyncInternal(cancellationToken);
if (_next != null)
{
await _next.StopAsync(cancellationToken);
}
}
protected abstract Task StartAsyncInternal(CancellationToken token);
protected abstract Task StopAsyncInternal(CancellationToken token);
}
创建所需数量的装饰器,
public class HostedServiceOneDecorator : MyHostedServiceDecorator
{
public HostedServiceOneDecorator(MyHostedServiceDecorator next) : base(next)
{
}
protected override async Task StartAsyncInternal(CancellationToken token)
{
Console.Write("This is my decorated start async!");
}
protected override async Task StopAsyncInternal(CancellationToken token)
{
Console.Write("This is my decorated stop async!");
}
}
在您注册的托管服务中,按如下方式致电装饰器:
public class MyHostedService : IHostedService
{
private readonly MyHostedServiceDecorator
_decorator;
public MyHostedService(MyHostedServiceDecorator decorator)
{
_decorator = decorator;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
// base StartAsync logic ...
await _decorator.StartAsync(cancellationToken);
}
public async Task StopAsync(CancellationToken cancellationToken)
{
// base StopAsync logic ...
await _decorator.StopAsync(cancellationToken);
}
}
最后,您通过在前一个构造器中传递下一个装饰器来注册服务及其装饰器。
services.AddSingleton<IHostedService, MyHostedService>();
services.AddSingleton<MyHostedServiceDecorator>(
new HostedServiceOneDecorator(new HostedServiceTwoDecorator(/*etc*/)));
所有装饰器都将以链状方式调用,直到没有下一个!
答案 4 :(得分:0)
我遇到了同样的问题,其中仅第一个不会调用IHostedService的多个实现。检查您是否恰好在IWebHostBuilder.ConfigureServices()方法而不是Add方法中使用TryAdd方法。第一个启用不允许接口的重复实现,第二个允许。这为我解决了这个问题。
所以使用这个:
webHost = WebHost
.CreateDefaultBuilder()
.ConfigureServices(x => x.Add(serviceCollection))
代替此:
webHost = WebHost
.CreateDefaultBuilder()
.ConfigureServices(x => x.TryAdd(serviceCollection))
答案 5 :(得分:0)
我遇到了一个稍微不同的问题,但是针对它的解决方案也可以在这里应用。我需要将服务实现注册为单例,并使其以IHostedService
的身份运行。基于哈维尔·卡佩罗的解决方案,我想到了这样的东西:
public class HostedServiceDecorator<T> : IHostedService where T : IHostedService
{
private readonly IHostedService _next;
public HostedServiceDecorator(T target)
{
_next = target;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
if (_next != null)
{
await _next.StartAsync(cancellationToken);
}
}
public async Task StopAsync(CancellationToken cancellationToken)
{
if (_next != null)
{
await _next.StopAsync(cancellationToken);
}
}
}
然后我可以做我所需要的:
services.AddSingleton<INetworkStatusService, NetworkStatusService>();
services.AddHostedService<HostedServiceDecorator<INetworkStatusService>>();
要回答这个问题,可以这样做:
services.AddTransient<NetworkStatusService>();
services.AddHostedService<HostedServiceDecorator<NetworkStatusService>>();