我只是想知道在DI期间是否可能有async/await
。
执行以下操作,DI无法解析我的服务。
services.AddScoped(async provider =>
{
var client = new MyClient();
await client.ConnectAsync();
return client;
});
以下内容完美无缺。
services.AddScoped(provider =>
{
var client = new MyClient();
client.ConnectAsync().Wait();
return client;
});
答案 0 :(得分:14)
Async / await在解析依赖关系时没有意义,因为:
这意味着所有涉及I / O的内容都应该推迟到构建对象图之后。
因此,不是注入连接的MyClient
,而是MyClient
第一次 时应该连接,而不是在创建它时连接。
<强>更新强>
由于您的MyClient
不是应用程序组件,而是第三方组件,这意味着您无法确保它{s}连接[s] 首次使用&#34;。
然而,这不应该是一个问题,因为Dependency Inversion Principle已经告诉我们:
摘要由上层/政策层拥有
这意味着应用程序组件不应直接依赖于第三方组件,而应依赖于应用程序本身定义的抽象。作为Composition Root的一部分,可以编写实现这些抽象的适配器,并将应用程序代码调整到第三方库。
这样做的一个重要优点是,您可以控制应用程序组件使用的API,这是成功的关键,因为它允许连接问题完全隐藏在抽象背后。
以下是您的应用程序定制抽象的示例:
public interface IMyAppService
{
Task<Data> GetData();
Task SendData(Data data);
}
请注意,此抽象缺少ConnectAsync
方法;这隐藏在抽象背后。例如,请查看以下适配器:
public class MyClientAdapter : IMyAppService
{
private readonly Lazy<Task<MyClient>> connectedClient;
public MyClientAdapter()
{
this.connectedClient = new Lazy<Task<MyClient>>(async () =>
{
var client = new MyClient();
await client.ConnectAsync();
return client;
});
}
public async Task<Data> GetData()
{
var client = await this.connectedClient.Value;
return await client.GetData();
}
public async Task SendData(Data data)
{
var client = await this.connectedClient.Value;
await client.SendData(data);
}
}
适配器从应用程序代码中隐藏有关连接的详细信息。它包含了MyClient
中Lazy<T>
的创建和连接,允许客户端只连接一次,而不管调用GetData
和SendData
方法的顺序如何,以及多少次。
现在,您可以让您的应用程序组件依赖于IMyAppService
而不是MyClient
,并将MyClientAdapter
注册为具有适当生活方式的IMyAppService
。