.NET Core DI 中的异步提供程序 [英] Async provider in .NET Core DI
问题描述
我只是想知道在 DI 期间是否可以使用 async/await
.
I'm just wondering if it's possible to have async/await
during DI.
执行以下操作,DI 无法解析我的服务.
Doing the following, the DI fails to resolve my service.
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;
});
推荐答案
虽然理论上可以在对象解析时使用 async/await,但在解析依赖时没有多大意义,因为:
Although it is theoretically possible to use async/await during object resolution, it doesn't make much sense when resolving dependencies, because:
- 构造函数不能是异步的,并且
- 对象图的构建应该简单、可靠且快速莉>
这意味着所有涉及 I/O 的事情都应该推迟到对象图构建完成之后.
This means that everything that involves I/O should be postponed until after the object graph has been constructed.
因此,与其注入连接的 MyClient
,MyClient
应该在第一次使用时连接,而不是在创建时连接.
So instead of injecting a connected MyClient
, MyClient
should connect when it is used for the first time, not when it is created.
由于您的 MyClient
不是一个应用程序组件,而是一个第三方组件,这意味着您无法确保它连接[s]是第一次使用."
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:
摘要归上层/策略层所有
the abstracts are owned by the upper/policy layers
这意味着应用程序组件不应直接依赖于第三方组件,而应依赖于应用程序本身定义的抽象.作为组合根的一部分,可以编写适配器来实现这些抽象并使应用程序代码适应第三方库.
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.
这样做的一个重要优势是您可以控制应用程序组件使用的 API,这是成功的关键,因为它允许将连接问题完全隐藏在抽象之后.
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, as 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:
public interface IMyAppService
{
Task<Data> GetData();
Task SendData(Data data);
}
请注意,此抽象缺少 ConnectAsync
方法;这隐藏在抽象背后.例如,看看以下适配器:
Do note that this abstraction lacks an ConnectAsync
method; this is hidden behind the abstraction. Take a look at the following adapter for instance:
public sealed class MyClientAdapter : IMyAppService, IDisposable
{
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);
}
public void Dispose()
{
if (this.connectedClient.IsValueCreated)
{
this.connectedClient.Value.Dispose();
}
}
}
适配器对应用程序代码隐藏了连接细节.它将 MyClient
的创建和连接包装在一个 Lazy
中,这允许客户端只连接一次,而与 GetData<的顺序无关/code> 和
SendData
方法被调用了多少次.
The adapter hides the connectivity details from the application code. It wraps the creation and connection of MyClient
in a Lazy<T>
, which allows the client to be connected just once, independently of in which order the GetData
and SendData
methods are called, and how many times.
这允许您让您的应用程序组件依赖于 IMyAppService
而不是 MyClient
并将 MyClientAdapter
注册为 IMyAppService
> 以适当的生活方式.
This allows you to let your application components depend on IMyAppService
instead of MyClient
and register the MyClientAdapter
as IMyAppService
with the appropriate lifestyle.
这篇关于.NET Core DI 中的异步提供程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!