如何在没有 BuildServiceProvider 的情况下直接从 ConfigureServices 访问 Singleton?

How to access Singleton directly from ConfigureServices without BuildServiceProvider?

如何从ConfigureServices访问单例?有几个配置我不能使用 appsettings 是有原因的。

例如,假设我想从数据库设置swagger标题和版本,而不是appsettings。我的实际问题是我想从我的数据库中设置领事地址。问题应该是一样的,我需要在 ConfigureServices 中访问我的数据库。我有一个这样的自定义扩展:

public static IServiceCollection AddConsulConfig(this IServiceCollection services, string address)
{
    services.AddSingleton<IConsulClient, ConsulClient>(p => new ConsulClient(consulConfig =>
    {
        consulConfig.Address = new Uri(address); 
    }));

    return services;
}

我从启动时调用它:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IGlobalParameter, GlobalParameterManager>();
    
    //I want to use IGlobalParameter here directly but without BuildServiceProvider
    //This part is the problem
    var service = ??
    var varTitle = service.GetById("Title").Result.Value;
    var varConsulAddress = service.GetById("ConsulAddress").Result.Value;
    
    services.AddConsulConfig(varConsulAddress);
    
    services.AddControllers();
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = varTitle, Version = "v1" });
    });
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // I can use it here or in the controller no problem
    var service = app.ApplicationServices.GetRequiredService<IGlobalParameter>();
    var varTitle = service.GetById("Title").Result.Value;
    var varConsulAddress = service.GetById("ConsulAddress").Result.Value;
}

不想使用BuildServiceProvider,因为它会产生多个实例,甚至visual studio也会给出警告。在

中引用

我从下面的 link 知道 IConfigureOptions 的存在 https://andrewlock.net/access-services-inside-options-and-startup-using-configureoptions/#the-new-improved-answer

但是,我似乎无法在 ConfigureService:

中找到确切的使用方法
public class ConsulOptions : IConfigureOptions<IServiceCollection>
{
    private readonly IServiceScopeFactory _serviceScopeFactory;
    public ConsulOptions(IServiceScopeFactory serviceScopeFactory)
    {
        _serviceScopeFactory = serviceScopeFactory;
    }

    public void Configure(IServiceCollection services)
    {
        using (var scope = _serviceScopeFactory.CreateScope())
        {
            var provider = scope.ServiceProvider;
            IGlobalParameter globalParameter = provider.GetRequiredService<IGlobalParameter>();
            var ConsulAddress = globalParameter.GetById("ConsulAddress").Result.Value;

            services.AddConsulConfig(ConsulAddress);
        }
    }
}

启动时设置:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IGlobalParameter, GlobalParameterManager>();
    services.AddSingleton<IConfigureOptions<IServiceCollection>, ConsulOptions>(); // So what? it's not called
    
    services.AddControllers();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // IConsulClient is still null here
}

有什么方法可以解决这个问题?

谢谢 Jeremy,就这么简单。我不知道为什么我花了太多时间弄清楚如何设置它

解决方法是添加单例:

services.AddSingleton<IConsulClient, ConsulClient>(
    p => new ConsulClient(consulConfig =>
    {
        var ConsulAddress = p.GetRequiredService<IGlobalParameter>().GetById("ConsulAddress").Result.Value;
        consulConfig.Address = new Uri(ConsulAddress);
    }
));