【问题标题】:Dependency Injection & connection strings / Multiple instances of a singleton依赖注入和连接字符串/单例的多个实例
【发布时间】:2022-02-14 20:24:27
【问题描述】:

我有一个严重依赖 Azure Cosmos DB 的 Web Api 项目。到目前为止,拥有一个 Cosmos DB 帐户(一个连接字符串)就足够了。现在一个新的要求是能够根据传入的参数连接到不同的 Cosmos(两个连接字符串)。

对于 customerId X,我们应该从 Cosmos DB 1 获取文档,对于另一个客户 Y,我们必须在 Cosmos DB 2 中查找。

到目前为止,我的 Startup.cs 文件注册了 CosmosClient 的单例实例。反过来又像这样实例化 cosmosClient = new CosmosClient(endpointUrl, primaryKey); 这非常有效。 Web Api 能够轻松处理所有请求。但是现在我们必须为每个请求新建一个 CosmosClient,性能真的很差。

所以我的问题是;有没有办法拥有同一个单例的多个实例?如;我们可以创建 Class+EndPointUrl 组合的单个实例吗? (那仍然是单例吗?)

现在,我们每分钟都会更新数千个 CosmosClients。与之前的相比,我们真的只需要多一个。

【问题讨论】:

  • 这可能会让你指向正确的方向。 devblogs.microsoft.com/cosmosdb/…
  • 在我们的应用程序中,我们最终创建了一个 CosmosClient 对象字典(键是帐户名)并注入了该字典的单例实例。
  • 只有 2 个数据库,您连接到一个或另一个取决于用户是谁?在这种情况下,我会在 Startup.cs 中注册两个 CosmosClient 实例,每个数据库一个,然后决定何时收到请求,使用这两个实例中的哪一个。
  • 您没有说您使用的是什么 DI 框架 - Autofac 很容易支持“键控”注册。 autofac.readthedocs.io/en/latest/advanced/keyed-services.html
  • 我正在使用标准的 .NET Framework DI。

标签: c# .net asp.net-web-api azure-cosmosdb dotnet-httpclient


【解决方案1】:

有多种方法可以做到这一点,但一个简单的实现是围绕您使用的每个 CosmosClient 创建一个包装器。包装器的唯一用途是允许您使用 CosmosClient 的各种实例并按类型区分它们。

//Create your own class for each client inheriting the behaviour of CosmosClient
public class ContosoCosmosClient : CosmosClient
{
    public ContosoCosmosClient(string connectionString, CosmosClientOptions clientOptions = null) : base(connectionString, clientOptions)
    {
    }

    public ContosoCosmosClient(string accountEndpoint, string authKeyOrResourceToken, CosmosClientOptions clientOptions = null) : base(accountEndpoint, authKeyOrResourceToken, clientOptions)
    {
    }

    public ContosoCosmosClient(string accountEndpoint, TokenCredential tokenCredential, CosmosClientOptions clientOptions = null) : base(accountEndpoint, tokenCredential, clientOptions)
    {
    }
}
//In Startup.up add a Singleton for each client
services.AddSingleton(new ContosoCosmosClient(...));
services.AddSingleton(new FabrikamCosmosClient(...));

然后在您的业务逻辑中,您可以添加两个客户端,并根据您的逻辑选择要使用的客户端:

public class MyService
{
    public MyService(ContosoCosmosClient contosoClient, FabrikamCosmosClient fabrikamClient)
    {
        //...
    }
}

【讨论】:

    【解决方案2】:

    感谢所有 cmets 和答案。

    最后,是不是这种情况,最好的解决方案是T先生建议的方法。https://devblogs.microsoft.com/cosmosdb/httpclientfactory-cosmos-db-net-sdk/

    我现在仍在使用一个 CosmosClient,Scoped。这允许动态使用端点。

    通过注入 IHttpClientFactory 并像这样设置 CosmosClientOptions;

      {
          HttpClientFactory = () => _httpClientFactory.CreateClient("cosmos")
      });
    

    我们现在正在充分利用 HttpClient 及其重用端口的能力。

    【讨论】:

    • 你能发布你的代码的扩展版本吗?使用命名的 HTTP 客户端如何让您连接到多个 cosmos 实例?你在哪里设置 cosmos 的连接字符串/你如何区分不同的连接?
    猜你喜欢
    • 1970-01-01
    • 2016-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-19
    • 1970-01-01
    • 2021-04-01
    相关资源
    最近更新 更多