How to inject a reference to a specific IHostedService implementation?

Turns out there's an easy way to do this (thanks for the pointer, Steven).

If you need to be able to inject / get a reference to some service, go ahead and register the service normally (without worrying about any IHostedService stuff):

services.AddSingleton<ServiceBusListener>();

Now we can register a separate hosted service whose only responsibility is to start/stop the service we just registered:

services.AddHostedService<BackgroundServiceStarter<ServiceBusListener>>();

Where BackgroundServiceStarter is a helper class that looks something like:

public class BackgroundServiceStarter<T> : IHostedService where T:IHostedService
{
    readonly T backgroundService;

    public BackgroundServiceStarter(T backgroundService)
    {
        this.backgroundService = backgroundService;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        return backgroundService.StartAsync(cancellationToken);
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return backgroundService.StopAsync(cancellationToken);
    }
}

Update 2018/8/6: updated code to avoid service locator pattern thanks to a suggestion from ygoe


Based on your answers, I made a helpful extension method. It allows to register an IHostedService with another interface.

The other interface doesn't need to implement IHostedService, so you don't expose the StartAsync() and StopAsync() methods

public static class ServiceCollectionUtils
{
    public static void AddHostedService<TService, TImplementation>(this IServiceCollection services)
        where TService : class
        where TImplementation : class, IHostedService, TService
    {
        services.AddSingleton<TService, TImplementation>();
        services.AddHostedService<HostedServiceWrapper<TService>>();
    }

    private class HostedServiceWrapper<TService> : IHostedService
    {
        private readonly IHostedService _hostedService;

        public HostedServiceWrapper(TService hostedService)
        {
            _hostedService = (IHostedService)hostedService;
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            return _hostedService.StartAsync(cancellationToken);
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            return _hostedService.StopAsync(cancellationToken);
        }
    }
}