webdevqa.jp.net

ASP.NET Core 3.1のConfigureServices()で使用するサービスを正しく解決する方法は?

ASP.NET Core 3.1ベースのアプリがあります。アプリの起動中、ConfigureServices(IServiceCollection services)でサービスを登録します。しかし、サービスの構成中に、データベースにある設定に基づいてアプリを起動したいと思います。

これが私のコードです

_public void ConfigureServices(IServiceCollection services)
{
    // Register context
    services.AddDbContext<AppDbContext>(options =>
    {
        options.UseMySql(Configuration.GetConnectionString("MySqlServerConnection"));
    });

    // Reister the setting provider
    services.AddSingleton<IAppSetting, AppSettings>();

    // Create a resolver which is WRONG!!
    var resolver = services.BuildServiceProvider();

    var setting = resolver.GetService<IAppSetting>();

    List<string> allowedCors = new List<string>()
    {
         setting.MainUrl.ToString()
    };

    if (setting.HasCustomAssetsUri)
    {
        allowedCors.Add(settings.AssetsUrl.ToString());
    }

    if (settings.HasCustomPhotosUri)
    {
        allowedCors.Add(settings.PhotosUrl.ToString());
    }

    services.AddCors(options =>
    {
        options.AddPolicy("AllowSubDomainTraffic",
        builder =>
        {
            builder.WithOrigins(allowedCors.ToArray())
                   .AllowAnyHeader()
                   .AllowAnyMethod();
        });
    });

    // More services
}
_

上記のコードを見るとわかるように、IAppSettingを登録していますが、すぐにデータベースにアクセスして現在の構成を取得したいと思っています。現在services.BuildServiceProvider()を呼び出して新しいリゾルバーを作成しています。このリゾルバーを使用して、IAppSettingのインスタンスを作成できます。

私のAppSetting実装は、登録されているAppDbContextにも依存しています。これが私のAppSettingです

_public class AppSetting : IAppSetting
{
    private AppDbContext context;

    public AppSetting(AppDbContext context)
    {
        this.context = context;
    }

    // methods...
}
_

BuildServiceProvider()を呼び出すと、シングルトンサービスの追加のコピーが作成されます。だから私はこれをしなくて済むようにしています。

ConfigureServices()メソッドでIAppSettingを正しく登録して解決し、それを使用してデータベース内の設定にアクセスするにはどうすればよいですか?

更新済み

Nkosiによって提示されたソリューションを使用しようとしましたが、次のエラーが発生しました

System.InvalidOperationException: 'ルートプロバイダーからスコープサービス' IAppSetting 'を解決できません。

以下は完全なスタックトレースです。

_This exception was originally thrown at this call stack:
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(System.Type, Microsoft.Extensions.DependencyInjection.IServiceScope, Microsoft.Extensions.DependencyInjection.IServiceScope)
    Microsoft.Extensions.DependencyInjection.ServiceProvider.Microsoft.Extensions.DependencyInjection.ServiceLookup.IServiceProviderEngineCallback.OnResolve(System.Type, Microsoft.Extensions.DependencyInjection.IServiceScope)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(System.Type, Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(System.Type)
    Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(System.IServiceProvider, System.Type)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(Microsoft.Extensions.DependencyInjection.ServiceLookup.FactoryCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext)
    Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitDisposeCache(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite, Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext)
    ...
    [Call Stack Truncated]
_
4
user12310517
services.AddSingleton<AppSetting>();
services.AddSingleton<IAppSetting>(ctx =>
    {
      var setting = ctx.GetRequiredService<AppSetting>();
      return setting;
    });