Mar*_*ert 0 c# dependency-injection autofac
我在 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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我使用 Autofac 定义 DI 容器,然后将其“分配”给提供程序类中的IServiceProvidervia :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() );
}
}
Run Code Online (Sandbox Code Playgroud)
我不清楚如何IServiceProvider向 DI 容器注册自身,以便将其注入到构造函数中。这可能吗?这似乎有点自我指涉,这可能会有问题。
我在网上看到的所有示例都要求引用 AutofacIContainer本身(或TestServiceProvider.Instance在我的示例中)。我可以做到这一点,但最终会将我的库与具体的服务提供者类联系起来。我想如果可以的话我想避免这种情况。
我意识到注入IServiceProvider被一些/许多人认为是一种反模式,尽管其他人认为它在工厂类中是可以接受的,因为工厂“简单地”扩展了 DI 容器。我对不依赖工厂类的其他方法持开放态度,只要它们允许我在运行时创建开放泛型类型的具体实例。
你有几个选择(没有双关语)。
builder.Populate()使用空集合进行调用该Autofac.Extensions.DependencyInjection包(您正在使用的包,因为您有AutofacServiceProvider)有一个扩展方法ContainerBuilder.Populate() ,该方法可以处理从 注册内容IServiceCollection并自动注册AutofacServiceProvider. 您可以使用空服务集合调用该方法,它会起作用。
builder.Populate(Enumerable.Empty<ServiceDescriptor>());
Run Code Online (Sandbox Code Playgroud)
这将为您提供您正在寻找的东西。然而,还有一个替代方案可以考虑......
ILifetimeScopeOptionFactory如果你是否与 Autofac 绑定无关紧要,你可以注入ILifetimeScope. Autofac 已自动注册当前生命周期范围,因此这将起作用:
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
}
Run Code Online (Sandbox Code Playgroud)
这样做的好处是您将获得 Autofac 提供的更丰富的解析选项,而无需任何额外的工作。缺点是您在这个级别上与 Autofac 相关联,这可能重要也可能不重要。
这可能只是您的示例,但如果您按照示例所示的方式直接从根容器进行解析,则需要了解一些重要信息:
你很容易就会出现严重的内存泄漏。
Autofac 保留IDisposable它解析的所有实例,以便在处置生命周期范围时可以安全地处置它们。如果您从容器中解析,这意味着任何内容都IDisposable将被保留,直到容器本身被释放为止,这对于大多数人来说是应用程序的生命周期。这意味着 - 假设 - 每个解决方案都可能只添加一点点内存,这些内存在容器被处置之前不会被处置。内存泄漏。
因此,我们建议始终从嵌套的生命周期范围而不是从容器进行解析。在网络应用程序中,请求级生命周期范围是完美的,因为它在请求后消失。在这样的示例中,由您和您的应用程序代码来确定集成生命周期范围的最佳方法。
当然,如果你百分百保证永远不会解决任何问题IDisposable,那就不用担心。