Как правильно разрешить службы для использования в ConfigureServices () в ASP. NET Core 3.1? - PullRequest
4 голосов
/ 06 февраля 2020

У меня есть приложение 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() приведет к созданию дополнительной копии одноэлементных сервисов. поэтому я стараюсь не делать этого.

Как правильно зарегистрировать, а затем разрешить IAppSetting в методе ConfigureServices(), чтобы я мог использовать его для доступа к настройкам, найденным в базе данных?

Обновлено

Я попытался использовать решение, представленное Nkosi, но получил следующую ошибку

System.InvalidOperationException: «Не удается разрешить службу с заданными областями 'IAppSetting' от root провайдера. '

Вот полная трассировка стека.

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]

Ответы [ 2 ]

3 голосов
/ 06 февраля 2020

Ссылка Использование служб DI для настройки параметров

Настройка параметров CORS с использованием DI, перемещение всех логи c в делегат конфигурации

//...

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

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

//configure CORS options using DI
services.AddOptions<CorsOptions>()
    .Configure<IServiceScopeFactory>((options, sp) => {
        using(var scope = sp.CreateScope()) {
            IAppSetting settings = scope.ServiceProvider.GetRequiredService<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());
            }
            options.AddPolicy("AllowSubDomainTraffic", builder => {
                builder.WithOrigins(allowedCors.ToArray())
                       .AllowAnyHeader()
                       .AllowAnyMethod();
            });
        }
    });

services.AddCors();

//...

, который Таким образом, теперь все отложено до того момента, когда они действительно необходимы, и вам не нужно преждевременно создавать набор служб.

0 голосов
/ 06 февраля 2020
services.AddSingleton<AppSetting>();
services.AddSingleton<IAppSetting>(ctx =>
    {
      var setting = ctx.GetRequiredService<AppSetting>();
      return setting;
    });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...