我在Net Core 3控制台应用程序中有一个工厂类,该类需要能够在运行时针对DI容器进行解析:
public class OptionFactory : IOptionFactory
{
private readonly IServiceProvider _svcProvider;
public OptionFactory( IServiceProvider svcProvider )
{
_svcProvider = svcProvider;
}
public IOption<T>? CreateOption<T>( params string[] keys )
{
// code eliminated for brevity
try
{
return retVal = _svcProvider.GetRequiredService<Option<T>>();
}
catch( Exception e )
{
return null;
}
}
}
我正在使用Autofac定义DI容器,然后通过提供程序类中的IServiceProvider
将其“分配”到new AutofacServiceProvider( builder.Build() )
:
public class TestServiceProvider
{
public static IServiceProvider Instance { get; private set; }
static TestServiceProvider()
{
var builder = new ContainerBuilder();
builder.RegisterType<OptionFactory>()
.As<IOptionFactory>()
.SingleInstance();
// code omitted for brevity
Instance = new AutofacServiceProvider( builder.Build() );
}
}
我不清楚如何在DI容器中注册IServiceProvider
本身,以便可以将其注入到构造函数中。那有可能吗?似乎有点自指,可能会出现问题。
我在网上看到的所有示例都要求引用Autofac IContainer
本身(或在我的示例中为TestServiceProvider.Instance
)。我可以做到,但是最终将我的库绑定到一个具体的服务提供者类。如果可以的话,我想避免该问题。
[我意识到注入IServiceProvider
在某些情况下被认为是反模式,尽管其他人认为在工厂级别可以接受,因为工厂在“简单”扩展DI容器。我愿意接受其他不依赖工厂类的方法,只要它们允许我在运行时创建开放泛型类型的具体实例即可。
您有几种选择(没有双关语😃)。
builder.Populate()
Autofac.Extensions.DependencyInjection
程序包(由于您具有AutofacServiceProvider
而正在使用)具有扩展方法ContainerBuilder.Populate()
which handles registering stuff from an IServiceCollection
and auto-registering the AutofacServiceProvider
。您可以使用空服务集合调用该方法,它将起作用。
IServiceCollection
这将为您提供所需的东西。但是,还有一种替代方法可以考虑...
AutofacServiceProvider
如果builder.Populate(Enumerable.Empty<ServiceDescriptor>());
是否绑定到Autofac都没关系,则可以注入ILifetimeScope
。 Autofac已自动注册了当前生存期范围,因此可以使用:
OptionFactory
这样做的好处是,您无需任何额外工作即可获得Autofac提供的更丰富的解决方案选项。缺点是您在此级别上只能使用Autofac,这可能会或可能不会重要。
这可能只是您的示例,但是要知道您是否要按照示例所示的方式直接从根容器中进行解析,这是很重要的一点:
您很容易以大量内存泄漏告终。
Autofac保留所有解析的ILifetimeScope
实例,以便在处置生存期范围时可以安全地处置它们。如果您要从容器中进行解析,则意味着public OptionFactory(ILifetimeScope scope)
{
// scope is whatever lifetime scope the
// factory itself came from - if that's the
// root container, then the scope is the
// container
}
将一直保留到容器自身被处置之前,这对大多数应用程序来说是生命周期。假设-这意味着-每个解决方案可能只添加了一点点的内存,直到容器被处置后才会被处置。内存泄漏。
因此,我们建议使用IDisposable
,而不要使用容器中的。在Web应用程序中,该请求级生存期范围是完美的,因为它在请求后消失了。在这样的示例中,取决于您和您的应用程序代码来确定集成生命周期作用域的最佳方法。
并且,当然,如果您绝对地,100%保证永远不会解决任何问题IDisposable
,请不用担心。