Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
412 views
in Technique[技术] by (71.8m points)

asp.net core - How to inject a reference to a specific IHostedService implementation?

My web app has a background service that listens to a service bus. Based on the docs, it looks like the built-in way to run a background service is to implement IHostedService.

So I have some code that looks like this:

public class ServiceBusListener : IMessageSource<string>, IHostedService
{
    public virtual event ServiceBusMessageHandler<string> OnMessage = delegate { };

    public Task StartAsync(CancellationToken cancellationToken)
    {
        // run the background task...
    }

    // ... other stuff ...
}

The service is then registered in Startup.cs with:

services.AddSingleton<IHostedService, ServiceBusListener>();

Once I update to ASP.NET 2.1 I can use the new convenience method:

services.AddHostedService<ServiceBusListener>();

But I believe the two are functionally equivalent.

The complication: my web app has multiple implementations of IHostedService (specifically, different instances of service bus listeners).

The question: how can I have some other component get a reference to a specific hosted service implementation (my service bus listener)? In other words, how do I get a specific instance injected into a component?

Use case: my background service listens for service bus messages and then re-publishes messages as .NET events (in case you're wondering, the consuming code deals with the threading issues). If the event is on the background service, then subscribers need to get a reference to the background service to be able to subscribe.

What I've tried: if I do the obvious thing and declare ServiceBusListener as a dependency to be injected into a different component, my startup code throws a "Could not resolve a service of type" exception.

Is it even possible to request a specific implementation of a IHostedService? If not, what's the best workaround? Introduce a third component that both my service and the consumer can reference? Avoid IHostedService and run the background service manually?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...