I'm just wondering if it's possible to have async/await
during DI.
Doing the following, the DI fails to resolve my service.
services.AddScoped(async provider =>
{
var client = new MyClient();
await client.ConnectAsync();
return client;
});
where as the following works perfectly fine.
services.AddScoped(provider =>
{
var client = new MyClient();
client.ConnectAsync().Wait();
return client;
});
Async/await doesn't make sense when resolving dependencies, because:
This means that everything that involves I/O should be postponed until after the object graph has been constructed.
So instead of injecting a connected
MyClient
,MyClient
should connect when it is used for the first time, not when it is created.Since your
MyClient
is not an application component but a third-party component, this means that you can't ensure that it "connect[s] when it is used for the first time."This shouldn't be a problem, however, because the Dependency Inversion Principle already teaches us that:
This means that application components should not depend on third-party components directly, but instead they should depend on abstractions defined by the application itself. As part of the Composition Root, adapters can be written that implement these abstractions and adapt application code to the third-party libraries.
An important advantage of this is that you are in control over the API that your application components use, which is the key to success here, a it allows the connectivity issues to be hidden behind the abstraction completely.
Here's an example of how your application-tailored abstraction might look like:
Do note that this abstraction lacks an
ConnectAsync
method; this is hidden behind the abstraction. Take a look at the following adapter for instance:The adapter hides the connectivity details from the application code. It wraps the creation and connection of
MyClient
in aLazy<T>
, which allows the client to be connected just once, independently of in which order theGetData
andSendData
methods are called, and how many times.This allows you to let your application components depend on
IMyAppService
instead ofMyClient
and register theMyClientAdapter
asIMyAppService
with the appropriate lifestyle.