如何在 ConfigureServices 中没有 BuildServiceProvider 的情况下解析存储库?

How to resolve repository without BuilderServiceProvider in ConfigureService?

我需要在 ConfigureService 方法中从存储库加载列表,而不是在 Configure 方法中。 我循环列表生成多个身份验证方案。

这是我加载列表的方法,它有效,但我已经警告 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;
}

是否可以在不使用 BuildServiceProvider() 的情况下解析和调用我的存储库?

ConfigureServices 是在服务提供者中注册服务的地方 - 正如错误消息所说 - 它不应该过早地构建服务提供者。

但是,您可以依赖ConfigureServices中的配置。因此,一个选项是将身份验证方案的设置移动到应用程序配置中。您可以使用 built-in 配置提供程序(例如 appsettings.json、环境变量等)并将设置存储在相应的位置。

如果这些不能满足您的要求,您还可以按照 here 所述创建自定义配置提供程序。该示例还展示了如何使用包含用于连接到数据库的连接字符串的临时配置。

谢谢 Markus,我按照 here 所述创建了自己的配置提供程序。

我在其中序列化设置数据(AuthenticationScheme、ValidIssuer 和一些其他属性....)的配置提供程序

    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));
        }
    }

配置源:

    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);
    }

配置生成器扩展:

    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));
        }
    }

接下来我在 Program.cs 中使用我的自定义配置:

builder.Configuration.AddCarrierConfiguration();

var settings = builder.Configuration.GetCarrierSetting();

GetCarrierSetting方法return列表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;
        }

所以像这样,我认为在 ConfigureServices 方法中加载数据而不调用 BuildServiceProvider.

是一个很好的做法