使用Autofac注册容器本身

22

我想知道将容器注册到自身是否有任何副作用。

IContainer container;
ContainerBuilder builder = new ContainerBuilder();
container = builder.Build();
builder.RegisterInstance(container).As<IContainer>();

然后像这样使用它

builder.RegisterType<IManagmentServiceImp>().As<ManagmentServiceImp>()
    .WithParameter(new ResolvedParameter(
            (pi, ctx) => pi.ParameterType == typeof(IContainer) && pi.Name == "Container",
            (pi, ctx) => container
));

或者它是否会起作用。

4个回答

43

你的代码不安全,因为你在初始化之前就注册了一个实例。

如果你需要在组件内部访问容器(这不是一个好主意),你可以依赖于ILifetimeScope接口,该接口有Resolve方法。

public class ManagmentServiceImp 
{
    public ManagmentServiceImp(ILifetimeScope scope)
    {
    }
}
ILifetimeScopeAutofac 中已经自动注册,无需进行额外的注册。
有关更多信息,请参见来自 Autofac 文档的控制作用域和生存期
顺便提一句,有依赖于您的 IoC 容器不是一个好的实践。这看起来像是使用了服务定位器反模式。如果您需要容器进行延迟加载依赖项,则可以使用具有Func<T>Lazy<T>的组合方式。
public class ManagmentServiceImp 
{
    public ManagmentServiceImp(Lazy<MyService> myService)
    {
        this._myService = myService; 
    }

    private readonly Lazy<MyService> _myService;
}
在这种情况下,当您首次访问时,将创建MyService
有关更多信息,请参见Autofac文档中的隐式关系

“Func”和“Lazy”的技巧真是太棒了!我不知道Autofac会自动提供它们。 - t3chb0t
一个工厂返回多个不同实例的情况怎么处理呢?可以使用Lazy<>来注入它们吗? - IngoB

15

你可以使用这个扩展方法:

public static void RegisterSelf(this ContainerBuilder builder)
{
    IContainer container = null;
    builder.Register(c => container).AsSelf().SingleInstance();
    builder.RegisterBuildCallback(c => container = c);
}

使用方法如下:builder.RegisterSelf();


使用该方法后,我在webapi核心中的第一个请求之后得到了“指定的CGI应用程序遇到错误并终止进程”,并且服务器无法处理之后的请求。更改为ILifetimeScope解决了这个问题。 - Adrian
1
从Autofac 5.0开始,这不再适用——.RegisterBuildCallBack()的签名已更改,现在提供了一个ILifetimeScope而不是IContainer。我仍在寻找可行的解决方案。 - Mr. T
2
IContainer 继承自 ILifetimeScope,因此进行强制转换可能会起作用... - Matthias Güntert

2

由于你需要提供容器的实例来使用builder.RegisterInstance(),因此你需要在将其作为参数传递之前初始化它,但是你目前没有这样做。然而,如果你将容器构建器结构化为在注册后(和容器初始化后)进行构建,则可以成功解决类中的容器实例。

请注意,这绝对是依赖注入中的设计问题,你绝不能这样做。你的容器/内核应该只存在于对象图的顶层。如果你开始注入容器,那么几乎肯定会走向服务定位器反模式。

void Main()
{
    IContainer container = new ContainerBuilder().Build();
    ContainerBuilder builder = new ContainerBuilder();

    builder.RegisterInstance(container).As<IContainer>();

    builder.RegisterType<ManagementServiceImp>().As<IManagmentServiceImp>()
       .WithParameter(new ResolvedParameter(
            (pi, ctx) => pi.ParameterType == typeof(IContainer) && pi.Name == "Container",
            (pi, ctx) => container
    ));

    container = builder.Build();
    var instance = container.Resolve<IManagmentServiceImp>();
}

public class ManagementServiceImp : IManagmentServiceImp 
{ 
    private IContainer _container;

    public ManagementServiceImp(IContainer Container)
    {
        _container = Container;
        _container.Dump();
    }
}

public interface IManagmentServiceImp { }

{btsdaf} - David L
{btsdaf} - torvin
{btsdaf} - David L
{btsdaf} - torvin

1
尝试使用容器解析IComponentContext ;)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接