【问题标题】:How to use async methods to create Cosmos Client in DI?如何使用异步方法在 DI 中创建 Cosmos 客户端?
【发布时间】:2021-07-03 16:02:47
【问题描述】:

我想在我的 ASP.net 5 WebAPI 项目中使用 Cosmos DB。要创建客户端,我想使用依赖注入将其注入到我的服务中。为此,我在 public void ConfigureServices(IServiceCollection services)

中创建了此声明
services.AddSingleton(async s => {
    var dbConfig = Configuration.GetSection("Database");
    var conn = dbConfig["ConnectionString"];
    var dbName = dbConfig["DbName"];
    if (string.IsNullOrEmpty(conn))
    {
       throw new ConfigurationErrorsException();
    }
    var client = new CosmosClient(conn);
    await client.CreateDatabaseIfNotExistsAsync(dbName);
    return client;
});

但在这种情况下,当我尝试通过以下方式注入服务时,我的服务出现错误:

public ProductService(ILogger<ProductService> logger, CosmosClient client)
{
    this._client = client;
    _logger = logger;
}

因为我的箭头函数返回Task&lt;CosmosClient&gt; 而不是CosmosClient。但是我该如何改变这种情况,因此数据库创建方法是异步的,我必须使用等待?!

谢谢

【问题讨论】:

  • 我已经在自己的代码中解决了这个问题,方法是使用创建方法为异步的工厂模式,然后从请求代码通过工厂获取客户端。工厂是非异步的,所以从 DI 中解析,然后需要客户端的请求可以异步创建客户端并使用它。
  • 由于客户端被注册为单例,我建议将异步操作移动到托管服务中以在启动时执行
  • 另一种选择是创建一个异步事件处理程序来创建数据库。看看这里的例子stackoverflow.com/a/59474646/5233410

标签: c# asp.net asp.net-core dependency-injection


【解决方案1】:

微软的依赖注入不支持async

我建议有一个单独的“schema deployer”项目作为部署的一部分运行(或在本地运行以在模拟器上创建数据库)。然后你可以删除CreateDatabaseIfNotExistsAsync调用并注入CosmosClient

如果您必须在应用程序中使用CreateDatabaseIfNotExistsAsync(而不是在部署期间),那么您将需要inject an asynchronous factory

public sealed class CosmosClientFactory
{
  private readonly Lazy<Task<CosmosClient>> _lazy;

  public CosmosClientFactory(Configuration configuration)
  {
    _lazy = new(async () =>
    {
      var dbConfig = configuration.GetSection("Database");
      var conn = dbConfig["ConnectionString"];
      var dbName = dbConfig["DbName"];
      if (string.IsNullOrEmpty(conn))
      {
       throw new ConfigurationErrorsException();
      }
      var client = new CosmosClient(conn);
      await client.CreateDatabaseIfNotExistsAsync(dbName);
      return client;
    });
  }

  public Task<CosmosClient> CreateAsync() => _lazy.Value;
}

用法:

private readonly CosmosClientFactory _clientFactory;
public ProductService(ILogger<ProductService> logger, CosmosClientFactory clientFactory)
{
  _clientFactory = clientFactory;
  _logger = logger;
}
public async Task DoSomethingAsync()
{
  var client = await _clientFactory.CreateAsync();
  await client.DoSomethingAsync();
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-21
    • 2021-06-11
    • 1970-01-01
    相关资源
    最近更新 更多