How to access singletons from ConfigureServices
? There's a reason that I can't use appsettings
for few configs.
For example, let's say that I want to set swagger title and version from database, not appsettings
. My actual problem is I want to set consul address from my database. The problem should be the same, that I need to access my database in ConfigureServices. I have a custom extension like this:
public static IServiceCollection AddConsulConfig(this IServiceCollection services, string address)
{
services.AddSingleton<IConsulClient, ConsulClient>(p => new ConsulClient(consulConfig =>
{
consulConfig.Address = new Uri(address);
}));
return services;
}
I call it from startup:
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;
}
I DO NOT want to use BuildServiceProvider as it will make multiple instances, even visual studio gives warning about it. referenced in How to Resolve Instance Inside ConfigureServices in ASP.NET Core
I knew the existence of IConfigureOptions from the following link https://andrewlock.net/access-services-inside-options-and-startup-using-configureoptions/#the-new-improved-answer
But, I can't seem to find how exactly do I use that in 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);
}
}
}
Set it in startup:
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
}
Any solution to how do I achieve this?
Thank you Jeremy, it's as simple as that. I don't know why I spend way too much time figuring out how to set this
The solution is to add singleton :
services.AddSingleton<IConsulClient, ConsulClient>(
p => new ConsulClient(consulConfig =>
{
var ConsulAddress = p.GetRequiredService<IGlobalParameter>().GetById("ConsulAddress").Result.Value;
consulConfig.Address = new Uri(ConsulAddress);
}
));