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.