I have a transient service that has to do async initialization (connecting to a different server).
It exposes a property public Task InitTask
which one can wait till the service is initlized.
It also exposes subservices that can be savely accessed after the InitTask
has finished.
public class Service
{
public Task InitTask { get; }
public ISubService1 SubService1 { get; }
public ISubService2 SubService2 { get; }
public ISubService3 SubService3 { get; }
}
All functionallity that the connection to the other server provides is capulated by these sub services. Normally I would inject the main service and then wait for it to be finished initlaization and then use one of these sub services. But I would like to just inject these subservices.
At first I tried
services.AddTransient<Service>()
.AddTransient(provider =>
{
var server = provider.GetService<Service>();
return server.SubService1;
})
.AddTransient(provider =>
{
var server = provider.GetService<Service>();
return server.SubService2;
})
.AddTransient(provider =>
{
var server = provider.GetService<Service>();
return server.SubService3;
});
but this has the obvious problem of not awaiting the InitTask
of the main service.
Then (since the sub-services are exposed via interfaces) I tried to code wrapper classes for the sub-services like
public class WrapperSubService1 : ISubService1
{
private readonly Service server;
public WrapperSubService1(Service server)
{
this.server = server;
}
private async ValueTask<ISubService1> GetSubService1Async()
{
await server.InitTask
return server.SubService1;
}
// interface implementations
public async Task<Example> GetExampleAsync(...)
{
var subService1 = await this.GetSubService1Async();
return await subService1.GetExampleAsync(...);
}
// many more (also some events and properties)
}
and do at startup
services.AddTransient<Service>()
.AddTransient<ISubService1, WrapperSubService1>()
.AddTransient<ISubService2, WrapperSubService2>()
.AddTransient<ISubService3, WrapperSubService3>();
but this has also an obvious flaw: code duplication.
What I would wish for would be something like:
services.AddTransient<Service>()
.AddTransient(async provider =>
{
var server = provider.GetService<Service>();
await server.InitTask;
return server.SubService1;
})
.AddTransient(async provider =>
{
var server = provider.GetService<Service>();
await server.InitTask;
return server.SubService2;
})
.AddTransient(async provider =>
{
var server = provider.GetService<Service>();
await server.InitTask;
return server.SubService3;
});
but this then exposes just Task<SubService1>
for injection.
Any ideas?