Reputation: 421
I need to load list from repository in ConfigureService method, not in Configure method. I loop list to generate multiple authentication scheme.
This is my method to load my list, it's works but I've Warning about builder.Services.BuildServiceProvider();
.
Calling 'BuildServiceProvider' from application code results in an additional copy of singleton services being created. Consider alternatives such as dependency injecting services as parameters to 'Configure'.
var listCarrierSetting = GetCarrierSetting();
List<Setting> GetCarrierSetting()
{
List<Setting> result = new();
try
{
var sp = builder.Services.BuildServiceProvider();
var settingRepository = sp.GetRequiredService<ISettingRepository>();
var task = Task.Run(async () => await settingRepository.GetAllWithDetails());
result = task.Result as List<Setting>;
}
catch (Exception)
{
//some code
}
return result;
}
Is it possible to resolve and call my repository without use BuildServiceProvider()
?
Upvotes: 1
Views: 1162
Reputation: 421
Thanks Markus, I create my own configuration provider as described here.
Configuration provider where I serialize settings data (AuthenticationScheme, ValidIssuer and some other properties....)
public class CarrierConfigurationProvider : ConfigurationProvider
{
private readonly string _connectionString;
public CarrierConfigurationProvider(string connectionString) =>
_connectionString = connectionString;
public override void Load()
{
var options = new DbContextOptionsBuilder<CarrierContext>()
.UseSqlServer(_connectionString).Options;
using var dbContext = new CarrierContext(options);
var lstSettings = dbContext.Settings.ToList();
Data = lstSettings.ToDictionary(c => $"SettingsCarrier:{c.Id}" , c => JsonConvert.SerializeObject(c));
}
}
Configuration Source :
public class CarrierConfigurationSource : IConfigurationSource
{
private readonly string _connectionString;
public CarrierConfigurationSource(string connectionString) =>
_connectionString = connectionString;
public Microsoft.Extensions.Configuration.IConfigurationProvider Build(IConfigurationBuilder builder) =>
new CarrierConfigurationProvider(_connectionString);
}
Configuration builder extension :
public static class ConfigurationBuilderExtensions
{
public static IConfigurationBuilder AddCarrierConfiguration(
this IConfigurationBuilder builder)
{
var tempConfig = builder.Build();
var connectionString =
tempConfig.GetConnectionString("CarrierSettingConnection");
return builder.Add(new CarrierConfigurationSource(connectionString));
}
}
Next I use my custom configuration in Program.cs :
builder.Configuration.AddCarrierConfiguration();
var settings = builder.Configuration.GetCarrierSetting();
And GetCarrierSetting
method who return a list of Setting
:
public static List<Setting> GetCarrierSetting(this IConfiguration configuration)
{
var result = configuration.AsEnumerable().Where(w => w.Key.StartsWith("SettingsCarrier:")).Select(s => s.Value);
List<Setting> lstSetting = new();
foreach(var item in result)
{
lstSetting.Add(JsonConvert.DeserializeObject<Setting>(item));
}
return lstSetting;
}
So like this, I think it's good practice to load data in ConfigureServices
method without call BuildServiceProvider
.
Upvotes: 0
Reputation: 22456
ConfigureServices
is the place to register the services in the service provider and - as the error message says - it should not build the service provider prematurely.
However, you can rely on the configuration in ConfigureServices
. So an option is to move the settings for the authentication schemes to application configuration. You can use a built-in configuration provider (e.g. for appsettings.json, environment variables, ...) and store the settings in the respective location.
If these do not work for your requirements, you can also create a custom configuration provider as described here. The sample also shows how to use a temporary config that contains a connection string for connecting to the database.
Upvotes: 1