[英]How can I resolve a registered Dependency from an Autofac Container in .NET Core 3.1
There's a project I'm trying to upgrade to .NET Core 3.1 from 2.2.有一个项目我正在尝试从 2.2 升级到 .NET Core 3.1。 My major issue is at the startup.cs where I'm registering dependencies with Autofac.我的主要问题是在 startup.cs 中,我正在向 Autofac 注册依赖项。 I have studied the documentation for registering dependencies in 3.0 and I understand it.我已经研究了在 3.0 中注册依赖项的文档并且我理解它。 But there is a requirement in ConfigureServices
method to register an object as an instance and it requires the container to resolve a registered service in the same method as seen in the code below但是ConfigureServices
方法要求将对象注册为实例,并且它要求容器以与下面代码中所示相同的方法解析注册的服务
Startup.cs (2.2)启动.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, I couldn't find a clear means of replicating the above with the new Autofac approach.在 .net core 3.1 中,我找不到使用新的 Autofac 方法复制上述内容的明确方法。
Startup (3.1)启动 (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
throws null reference at runtime. this.AutofacContainer
在运行时抛出空引用。 I am not surprised by this because ConfigureServices
executes before Configure
method where I get references to the registered dependencies in the container.我对此并不感到惊讶,因为ConfigureServices
在Configure
方法之前执行,在那里我可以获取对容器中已注册依赖项的引用。 I can't seem to find a way to resolve IHttpContextAccessor
from the container in ConfigureServices
and use it as it is in netcore 2.2.我似乎无法找到一种方法来从ConfigureServices
的容器解析IHttpContextAccessor
并像在 netcore 2.2 中一样使用它。
For clarity, Please see how the executionContextAccessor
is used in the class that does the initialization as done in netcoreapp2.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();
}
}
}
You could do the following in Configure
although I wouldn't recommend it as you're splitting the responsibility of registering your dependencies across multiple parts of your startup.您可以在Configure
执行以下Configure
尽管我不建议这样做,因为您将在启动的多个部分中注册依赖项的责任分开。 This will resolve the IHttpContextAccessor through IApplicationBuilder.GetServce<TService>()
which you can then use for subsequent registrations.这将通过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);
}
Likewise, you could also resolve the IExecutionContextAccessor in order to add registrations like so.同样,您也可以解析 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);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.