Как разрешить зарегистрированную зависимость от контейнера Autofa c в. NET Core 3.1 - PullRequest
0 голосов
/ 04 февраля 2020

Есть проект, который я пытаюсь обновить до. NET Core 3.1 с 2.2. Моя главная проблема - в файле startup.cs, где я регистрирую зависимости с помощью Autofa c. Я изучил документацию для регистрации зависимостей в 3.0, и я это понимаю. Но в методе ConfigureServices есть требование зарегистрировать объект как экземпляр, и он требует, чтобы контейнер разрешил зарегистрированную службу тем же методом, как показано в приведенном ниже коде

Startup.cs ( 2.2)

public IServiceProvider ConfigureServices(IServiceCollection services)
{

    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    services.AddSingleton<IExecutionContextAccessor, ExecutionContextAccessor>();

    //other services registered

    return CreateAutofacServiceProvider(services);
}

private IServiceProvider CreateAutofacServiceProvider(IServiceCollection services)
{
    var containerBuilder = new ContainerBuilder();

    containerBuilder.Populate(services);

    containerBuilder.RegisterModule(new MyModule());

    var container = containerBuilder.Build();

    var httpContextAccessor = container.Resolve<IHttpContextAccessor>();
    var executionContextAccessor = new ExecutionContextAccessor(httpContextAccessor);

    var emailsConfiguration = new EmailsConfiguration(_configuration["EmailsConfiguration:FromEmail"]);

    // executionContextAccessor is used to initialize some modules here

    return new AutofacServiceProvider(container);
}

In. net core 3.1, я не смог найти четкого способа повторить вышесказанное с новым подходом Autofa c.

Запуск (3.1)

public ILifetimeScope AutofacContainer { get; private set; }

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    services.AddSingleton<IExecutionContextAccessor, ExecutionContextAccessor>();

    // other services registered

    var httpContextAccessor = this.AutofacContainer.Resolve<IHttpContextAccessor>();
    var executionContextAccessor = new ExecutionContextAccessor(httpContextAccessor);

    var emailsConfiguration = new EmailsConfiguration(_configuration["EmailsConfiguration:FromEmail"]);

    // executionContextAccessor is used to initialize some modules here
}

public void ConfigureContainer(ContainerBuilder containerBuilder)
{
    containerBuilder.RegisterModule(new MyModule());
}

public void Configure(IApplicationBuilder app, IHostEnvironment env)
{
    this.AutofacContainer = app.ApplicationServices.GetAutofacRoot();

    // other stuff
}

this.AutofacContainer выбрасывает нулевую ссылку во время выполнения. Меня это не удивляет, потому что ConfigureServices выполняется до метода Configure, где я получаю ссылки на зарегистрированные зависимости в контейнере. Кажется, я не могу найти способ разрешить IHttpContextAccessor из контейнера в ConfigureServices и использовать его как есть в netcore 2.2.

Для ясности, пожалуйста, посмотрите, как executionContextAccessor используется в класс, который выполняет инициализацию, как в netcoreapp2.2:

public class ModuleStartup
{
    private static IContainer _container;

    public static void Initialize(
        IExecutionContextAccessor executionContextAccessor,
        EmailsConfiguration emailsConfiguration)
    {
        ConfigureCompositionRoot(
            executionContextAccessor,
            emailsConfiguration);
    }

    private static void ConfigureCompositionRoot(
        IExecutionContextAccessor executionContextAccessor,
        EmailsConfiguration emailsConfiguration)
    {
        var containerBuilder = new ContainerBuilder();

        containerBuilder.RegisterModule(new EmailModule(emailsConfiguration)); 

        containerBuilder.RegisterInstance(executionContextAccessor);

        _container = containerBuilder.Build();

        ModuleCompositionRoot.SetContainer(_container);
    }

    Internal static class ModuleCompositionRoot
    {
        private static IContainer _container;

        internal static void SetContainer(IContainer container)
        {
            _container = container;
        }

        internal static ILifetimeScope BeginLifetimeScope()
        {
            return _container.BeginLifetimeScope();
        }
    }
}
...