问题 解决Module类中的AutoFac依赖项


我是AutoFac的新手,目前我在app app中使用自定义模块来启动一些核心F#系统。我正在使用的代码是

var builder = new ContainerBuilder();
builder.RegisterType<DefaultLogger>().As<IDefaultLogger>();
builder.RegisterModule(new ConfigurationSettingsReader("autofac"));
builder.Build();

在我的app配置中,我有适当的逻辑来启动相关系统。我想访问我的模块中的DefaultLogger。 Module基类的元数据有以下选项可供我使用:

protected virtual void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration);

protected virtual void AttachToRegistrationSource(IComponentRegistry componentRegistry, IRegistrationSource registrationSource);

public void Configure(IComponentRegistry componentRegistry);

protected virtual void Load(ContainerBuilder builder);

到目前为止我只使用Load,我在构建器上看不到任何允许我进入日志记录服务的方法。


11700
2018-05-01 14:19


起源

这是一个重复的问题 stackoverflow.com/questions/23413211/... ? - Travis Illig


答案:


使用autofac而不是使用RegisterType方法在模块中注册某些内容时,可以使用Register方法:

builder.Register(c =>
   {
       IComponentContext ctx = c.Resolve<IComponentContext();
       IDefaultLogger logger = ctx.Resolve<IDefaultLogger>();
       ...do something with logger...
       return ...return object you want to register...;
    });

6
2018-05-01 15:08



这对我描述的场景并没有多大帮助。我知道我可以使用IComponentContext解析依赖关系,但我需要访问Module内的一个。 - Jesse Carter
您不能将焦点留在此处以在外部范围(其示例中的模块)中设置变量。这样您只能登录注册。无论如何,这个片段显示了使用容器/上下文的“正确方法”,所以+1。也许Jesse需要使用生命周期范围和一个具有记录器的容器,并构建另一个容器,该容器将注入记录器本身加载第一个提供的模块(嗯,听起来太复杂了)。 - Beachwalker


答案结果非常简单。我刚刚将IComponentContext添加为Module的实现的依赖项

public class LocalActorSystemModule : Module {
    private IComponentContext m_ComponentContext; // A service for resolving dependencies required by this module

    public LocalActorSystemModule(IComponentContext componentContext) { 
        m_ComponentContext = componentContext;
    }

让AutoFac为我注入IComponentContext。这样我就可以解决模块内部所需的任何依赖关系。


2
2018-05-01 15:49



你将如何注册LocalActorSystemModule? - Rushi Soni
这对我不起作用。我通过Module构造函数注入了IComponentContext,但是当我尝试使用它时 AttachToComponentRegistration 它无法解决我想要的东西,因为组件尚未注册。 - emragins
如果模块本身已注册并且在加载(必需的依赖项,例如模块已加载)之后,这仅适用于模块,否则您无法解决。恕我直言,IComponentContext应该被注入服务注册(自动),但不能用于模块。我认为这种行为不是真的可以预测,我不建议这样做。考虑在模块未实际加载时使用IComponentContext ...加载前后的结果是什么? - Beachwalker
一个改进可能是显式声明模块在ctor中需要的每个依赖项 - 而不是仅仅传递整个IComponentContext。 - Schneider


使用经验法则 每个IoC / DI 容器: 解决一次! =>然后,您将获得所请求对象的所有依赖项。如果你试图多次解决,注册其他对象(在此期间)你陷入了地狱。真。如果您想在不同的地点和时间点(从中央注册解决)检索不同目的的对象,您可能正在寻找 服务定位器模式 相反(但这通常被描述为 反模式,也)。

模块的目的是将相关的注册(有条件地)捆绑为 Autofac文档

模块是一个小类,可用于捆绑一组   “Facade”背后的相关组件,以简化配置和   部署。

...因此,如果它们只是注册的总和并且容器尚未构建,则您无法立即解析并使用(甚至以前注册过的)组件(除了通过OnActivate *钩子调用注册人本身的方法或当使用实例注册时,但我认为这不是你的例子的情况)。组件处于注册状态,但完整的上下文尚未准备好解决。如果您覆盖另一个模块中的注册会发生什么?然后你会注入不同的对象......糟糕的主意。也许您应该重新考虑您的应用程序设计以及哪些对象具有哪些职责。

顺便说一句:日志记录是一个跨领域的问题,通常通过调用单独的静态工厂或服务而不是进行构造函数/属性注入来“注入/解决”(请参阅 Common.Logging 例如)。

public class MyModule : Module
{
    private static readonly ILog Log = LogManager.GetLogger<MyModule>();

    protected override void Load(ContainerBuilder builder)
    {
        Log.Debug(msg => msg("Hello")); // log whatever you want here
    }
}

您也可以尝试使用 AOP 库并将依赖项编织到模块中(使用反射)。但我认为仅仅尝试登录模块是不值得的。

无论如何:@ mr100已经在注册期间显示了正确的用法。在那里你也可以处理激活等但不能记录模块本身。


2
2018-01-14 13:56