无论如何在运行时向服务提供者添加服务?还是重建它?在 .NET 5.0 或 .NET Core 3+ 上

Is there anyway to add services to the service provider at runtime? Or rebuild it? On .NET 5.0 or .NET core 3+

我有一个基于微服务架构设计的多租户应用程序。

我想注入 X 数量的服务,具体取决于租户数量 运行。

 public void ConfigureServices(IServiceCollection services)
    {
        // ... OTHER DI

        services.AddHttpClient("TenantsService")
            .AddTypedClient<ITenantServiceClient>(c => new TenantServiceClient(new TenantServiceClientSettings()
            {
                AccessKey = Configuration["TenantsService:ApiKey"],
                BaseUrl = new Uri(Configuration["TenantsService:Url"])
            }, c)); 

        foreach (var tenant in TenantsToRegister)
        {
            services
                .AddGraphQLServer($"{tenant.Name}");
        }

        ...

    }

如果我在应用程序启动时有租户列表,上面的代码就可以工作。但我需要从另一个微服务请求该列表。有了这个约束,我需要构建服务提供者才能获得该列表。同时我需要服务商build之前的list来注入我需要的服务

我看到的唯一选择是在运行时添加服务,但我不确定是否可行。

您有问题...您正在尝试在多租户环境中垂直扩展。你会和 10 个租户一起做吗? 100?对于单个节点上的单个进程来说,这是大量的 ram(如果你 100% 确定你会拥有其中的一些,则可能不是这种情况)没有任何机会水平扩展

我认为您可以从相同的图像创建每个租户的服务,但不同的配置和 api gateway/loadbalancer 取决于...某事...(Header,查询参数,用户 ID 等)。它可能需要一些基础设施投资,但在未来不会是一个痛苦

如果您真的想从 http 客户端加载租户信息,然后为每个租户添加 HC gql 服务器,我建议您编写自己的 IConfiguration 提供程序。

这是 Consul 集成,它具有与您需要的相同的 http 往返 https://github.com/wintoncode/Winton.Extensions.Configuration.Consul。它添加自定义配置源并在启动时加载它

之后,您只需在启动时从配置中映射您的租户信息

From a architectual point of view I would recommend to use "real" services for each tenant. For example start a docker or a process of your application per tenant. Like written in a former answer (thanks to sergey).

如果你真的想在同一个进程中为每个租户启动一个新的 GraphQLServer 那么我会这样做: Full example on dotnet fiddle

services
    .AddHttpClient("TenantsService")
    .AddTypedClient<ITenantServiceClient>(c => 
                                    new TenantServiceClient(new TenantServiceClientSettings
                                    {
                                        AccessKey = "THE KEY", // Configuration["TenantsService:ApiKey"], 
                                        BaseUrl = new Uri("https://the-uri-you-need.com") // new Uri(Configuration["TenantsService:Url"])
                                    }, c));
        
// build a temporary service provider before, with all services added until now.
var tempServiceProvider = services.BuildServiceProvider();

// resolve the tenant service and query for tenants
var tenantsToRegister = tempServiceProvider.GetRequiredService<ITenantServiceClient>().GetTenants();

// register needed tenants
foreach (var tenant in tenantsToRegister)
{
    services.AddGraphQLServer($"{tenant}");
}

...当然,必须添加围绕对 ITenantServiceClient 的调用的整个错误处理,但这仅用于演示目的。 这里的特殊之处在于中间 IServiceProvider,它使您能够使用全套 DI 来查询您的租户,但之后您可以添加所需的租户。

但是:这也是在启动时,运行时不能添加额外的服务器。

更新 这是 updated dotnet fiddle(感谢 joao-figueira)