I配置DI先有鸡还是先有蛋的问题

问题描述 投票:0回答:1

我有一个用 C# 编写的 ASP.NET Core 7 MVC 应用程序。我想建立一个自定义

IConfiguration
以添加到已注册的提供者中。

我想使用DI服务集合中注册的一些服务来实现一些配置提供者。这些服务通常会从

IConfiguration
提供者那里获取价值。

我想使用使用现有

IConfiguration
提供者的信息配置的服务来引导新的
IConfiguration
,然后我想使用新的
IConfiguration
提供者来配置我想添加到服务集合中的更多服务。

我可能想添加一个基于存储库的

IConfiguration
,它需要一个连接字符串到存储库,例如,我可能想在存储库中保留其他服务的设置。存储库需要一些访问服务,也许是 EF。

天真地我可以尝试实例化一个“临时”服务提供者,使用临时服务构建配置提供者,将其添加到已注册的配置中,然后添加更多服务。这对我来说似乎不是一个好主意,特别是如果我有单例和作用域服务。

有没有办法真正使用服务提供者,然后添加更多服务,然后再次使用它?还是我疯了?

c# dependency-injection asp.net-core-mvc inversion-of-control .net-7.0
1个回答
0
投票

是的,您可以使用服务提供者配置一个 IConfiguration 实例,然后使用该实例配置更多服务以添加到服务集合中。您可以使用以下步骤实现此目的:

  1. 创建一个自定义的 IConfigurationSource 实现,它使用注册的服务来配置配置数据。例如,您可以创建一个 RepositoryConfigurationSource,它将 IRepositoryAccessService 作为构造函数参数,并使用该服务从存储库中检索配置数据。
public class RepositoryConfigurationSource : IConfigurationSource
{
    private readonly IRepositoryAccessService _repositoryAccessService;

    public RepositoryConfigurationSource(IRepositoryAccessService repositoryAccessService)
    {
        _repositoryAccessService = repositoryAccessService;
    }

    public IConfigurationProvider Build(IConfigurationBuilder builder)
    {
        var data = _repositoryAccessService.GetConfigurationData();
        return new MemoryConfigurationProvider(new MemoryConfigurationSource
        {
            InitialData = data
        });
    }
}
  1. 通过在 Startup.cs 文件中的 ConfigurationBuilder 实例上调用 Add,向 DI 容器注册自定义 IConfigurationSource。
public void ConfigureServices(IServiceCollection services)
{
    // Register other services...

    // Register the repository access service and the custom IConfigurationSource
    services.AddSingleton<IRepositoryAccessService, MyRepositoryAccessService>();
    services.AddConfiguration(config =>
    {
        config.Add(new RepositoryConfigurationSource(services.BuildServiceProvider().GetRequiredService<IRepositoryAccessService>()));
    });

    // Add more services that depend on the configuration data...
}
  1. 使用 IConfiguration 实例来配置依赖于配置数据的附加服务。例如,您可以添加一个 IMyService 实现,它将一些配置数据作为构造函数参数。

public class MyService : IMyService
{
    public MyService(IConfiguration configuration)
    {
        // Use configuration data to configure the service
    }
}

public void ConfigureServices(IServiceCollection services)
{
    // Register other services...

    // Register the repository access service and the custom IConfigurationSource
    services.AddSingleton<IRepositoryAccessService, MyRepositoryAccessService>();
    services.AddConfiguration(config =>
    {
        config.Add(new RepositoryConfigurationSource(services.BuildServiceProvider().GetRequiredService<IRepositoryAccessService>()));
    });

    // Add more services that depend on the configuration data...
    services.AddSingleton<IMyService, MyService>();
}

请注意,在此示例中,我们创建了一个临时的 ServiceProvider 实例,以便检索 IRepositoryAccessService 实例以传递给 RepositoryConfigurationSource 构造函数。这是必要的,因为我们不能直接将服务注入 IConfigurationSource 实例,但这确实意味着 IRepositoryAccessService 实例将在释放临时 ServiceProvider 时被释放。如果您需要在应用程序的生命周期内保持服务实例处于活动状态,您可以将其注册为单例,而不是从临时 ServiceProvider 中检索它。

© www.soinside.com 2019 - 2024. All rights reserved.