如何从.NET Core 3.1中的Autofac容器解析注册的依赖项

时间:2020-02-04 09:47:16

标签: c# autofac asp.net-core-3.0 asp.net-core-3.1

有一个项目正在尝试从2.2升级到.NET Core 3.1。我的主要问题是在startup.cs上,我正在其中向Autofac注册依赖项。我已经研究了在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);
}

在.net core 3.1中,我找不到使用新的Autofac方法复制以上内容的明确方法。

启动(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在运行时引发空引用。我对此并不感到惊讶,因为ConfigureServicesConfigure方法执行之前得到了容器中已注册的依赖项的引用。我似乎找不到一种方法来从IHttpContextAccessor的容器中解析ConfigureServices并像在netcore 2.2中一样使用它。

为清楚起见,请参见在netcoreapp2.2中完成初始化的类中如何使用executionContextAccessor

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

1 个答案:

答案 0 :(得分:0)

您可以在 Configure 中执行以下操作,但我不建议这样做,因为您将注册依赖项的责任分散到启动的多个部分。这将通过 IApplicationBuilder.GetServce<TService>() 解析 IHttpContextAccessor,然后您可以将其用于后续注册。

public void Configure(IApplicationBuilder app, IHostEnvironment env)
        {
            var httpContextAccessor = app.ApplicationServices.GetService<IHttpContextAccessor>();
            var executionContextAccessor = new ExecutionContextAccessor(httpContextAccessor);
            var emailsConfiguration = new EmailsConfiguration(_configuration["EmailsConfiguration:FromEmail"]);

            ModuleStartup.Initialize(executionContextAccessor, emailsConfiguration);
        }

同样,您也可以解析 IExecutionContextAccessor 以添加这样的注册。

        public void Configure(IApplicationBuilder app, IHostEnvironment env)
        {
            var httpContextAccessor = app.ApplicationServices.GetService<IHttpContextAccessor>();
            var executionContextAccessor = new ExecutionContextAccessor(httpContextAccessor);

            var fooToRegister = new Foo(executionContextAccessor);

            var registration = RegistrationBuilder
                .ForDelegate<IAnotherInterface>((c, p) => fooToRegister)
                .InstancePerLifetimeScope()
                .CreateRegistration();

            app.ApplicationServices
                .GetAutofacRoot().ComponentRegistry
                .Register(registration);
        }