It sort of breaks the IoC pattern to register bindings asynchronously. You'll need to incorporate the async settings into a wrapper class. This wrapper class should be responsible for:
- loading the settings
- providing the actual implementation of
IMyService
If IMyService
has synchronous methods, then you'll probably have to change it, either to provide async versions of all the methods, or to provide a Ready
property + event, so that consumers will know when it is safe to access. But if it's a service, its methods are probably already async, right?
As an illustration, let's call the wrapper class MyServiceWrapper
. It will load the settings when it is first constructed, and pass through all asynchronous methods in IMyService
(for example, SomeMethodAsync
as below).
public interface IMyService
{
Task SomeMethodAsync(Action<bool> callback);
}
public class MyServiceWrapper : IMyService
{
private IMyService _impl = null;
private IMyService _remote, _local;
private bool _loaded = false;
private object _sync = new object();
public Task SomeMethodAsync(Action<bool> callback)
{
// first make sure the settings have been loaded
await LoadSettings();
_impl.SomeMethodAsync(callback);
}
public MyServiceWrapper(MyRemoteService remoteService, MyLocalService localService)
{
_remote = remoteService;
_local = localService;
LoadSettings();
}
private async Task<bool> LoadSettings()
{
if (_loaded)
return true;
// lock to prevent multiple threads from loading the settings
lock (_sync)
{
if (_loaded)
return true;
if(await SettingsManager.LoadSettings().EnableRemote)
_impl = _remote;
else
_impl = _local;
}
return true;
}
}
Now you can have your DI container register:
MyRemoteService
->MyRemoteService
MyLocalService
->MyLocalService
IMyService
->MyServiceWrapper