Home > front end >  How to inject an IEnumerable<Interface> which is also a hosted service as singleton lifetime
How to inject an IEnumerable<Interface> which is also a hosted service as singleton lifetime

Time:10-06

I am looking to leverage off .Net Core taking care of the lifetime of services which are the same as the whole app and I want to inject them into another hosted service. I know that I could just implement the start/stop of the listeners myself in the Server's start/stop. But it feels unnecessary if I could the below scenario to work.

I would prefer to get it down to a single line for the registration. I was playing around with creating Extension methods to the IServiceCollection.

public class Server: IHostedService
{
    public Server(IEnumerable<IConnectionListener> listeners)
    {
        foreach(var l in listeners) 
        {
            l.Connected  = HandleConnection;
        }
    }

    private void HandleConnection(object src, Foo foo) { }

    public async Task StartAsync(CancellationToken ct)
    {}

    public async Task StopAsync(CancellationToken ct)
    {}
}


public interface IConnectionListener
{
    event ConnectionHandler Connected;
}

public class ConnectionListener: BackgroundService, IConnectionListener
{
    public async Task ExecuteAsync(CancellationToken ct)
    {
         // Open TcpListener and register with the ct to stop the listener.
    }
}

public class SslConnectionListener: BackgroundService, IConnectionListener
{
    public async Task ExecuteAsync(CancellationToken ct)
    {
         // Open TcpListener and register with the ct to stop the listener.
         // Add some extra SSL stuff
    }
}

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices((hc, services) => 
        {
            // This appears to work. But I have concerns about whether the life times will truly
            // be singleton and automatic disposal of the objects (having used the factory, I do
            // want the automatic disposal by the container).
            var listener = new ConnectionListener();
            var sslListener = new SslConnectionListener();
            services.AddSingleton<IConnectionListener>(sp => listener);
            services.AddSingleton<IConnectionListner>(sp => sslListener);

            services.AddHostedService(sp => listener);
            services.AddHostedService(sp => sslListener);

            // This doesn't work
            services.AddHostedService<SslConnectionListener>();
            services.AddHostedService<ConnectionListener>()
            services.AddHostedService<Server>();
        }

CodePudding user response:

The container is not creating this instance:

var listener = new ConnectionListener();

If you want it as a singleton, just use the resolver because you're already at the root:

services.AddSingleton<IConnectionListener, ConnectionListener>();
services.AddHostedService(resolver => { return resolver.GetService<IConnectionListener>(); });

Guaranteed to be a singleton

CodePudding user response:

You could consider this approach

//register the instances
services.AddSingleton<ConnectionListener>();
services.AddSingleton<SslConnectionListener>();
//register their abstractions
services.AddSingleton<IConnectionListener>(sp => sp.GetService<ConnectionListener>());
services.AddSingleton<IConnectionListener>(sp => sp.GetService<SslConnectionListener>());
//register hosted services.
services.AddHostedService(sp => sp.GetService<ConnectionListener>());
services.AddHostedService(sp => sp.GetService<SslConnectionListener>());
services.AddHostedService<Server>();

This way the container manages the entire lifetime of the created instances.

This could be neatly wrapped in an extension method to simplify the call.

  • Related