IHostedService的多种实现

时间:2018-10-09 02:05:47

标签: c# asp.net-core asp.net-core-2.0

我正在尝试使用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>();

6 个答案:

答案 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)

保持异步!如此处所述...

https://github.com/aspnet/Hosting/issues/1560

{{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>>();