【发布时间】:2012-07-13 02:54:36
【问题描述】:
我有一个基础控制器类,它向它的子类公开了一些日志记录功能。此日志记录依赖项是构造函数注入的。为了提供一些简化的代码,这就是它的样子:
public abstract class LogControllerBase : Controller
{
private readonly ILogger logger = null;
protected LogControllerBase(ILogger logger)
{
this.logger = logger;
}
}
我的子控制器也有自己的依赖项,因此它们看起来像这样:
public class SomeController : LogControllerBase
{
private readonly IService service = null;
[ImportingConstructor]
public SomeController(ILogger logger, IService service)
: base(logger)
{
this.service = service;
}
}
我使用这些构造函数来简化单元测试中的依赖注入,但在生产中,所有组合都(应该)由 MEF 完成。我正在使用我的自定义控制器工厂类,它使用 MEF 来实例化控制器。
总结一下:
- 我有一个基本的抽象控制器类,它有自己的依赖项
- 我有后代控制器使用导入来获取由 MEF 注入的参数(即它们的依赖项以及基类的依赖项)
- 单元测试不使用 MEF,因此将模拟注入到构造函数参数中
问题
这一切对我来说都成立,但 MEF 的想法不同。当我编译并运行这段代码时,我得到了这个异常:
在先决条件导入 'SomeController..ctor (Parameter="logger", ContractName="ILogger")' 设置之前无法调用 GetExportedValue。
所有用作构造函数参数的接口类型都设置了属性InheritedExport,并且还具有具体的实现,因此应该可以按预期工作。
不同的工作替代方案
当我通过直接在这些私有字段上执行导入来尝试另一种方法时,一切似乎都正常。
public abstract class LogControllerBase : ControllerBase
{
[Import]
private ILogger logger = null;
protected LogControllerBase() { }
}
public class SomeController : LogControllerBase
{
[Import]
private IService service = null;
public SomeController() { }
}
所以这可行,但不一样...我可以在此处添加构造函数以进行依赖注入,但是我将有两组构造函数,并且在进行单元测试时可能会使用无参数构造函数,这当然是错误的因为不会设置任何依赖项。不是真实的,也不是模拟的。
问题
如何通过将依赖注入构造函数设置为 ImportingConstructor 在构造函数中注入具体实现来说服 MEF 创建我的控制器?
【问题讨论】:
-
@Steven:很遗憾,这是不可能的,因为 MEF 是由更高级别的库设置的内部策略,必须在我的 Web 应用程序中使用。说实话,考虑到与此应用程序相关的其他要求,我自己也会选择 MEF。它还有其他一些用其他静态定义的 DI 容器无法轻松实现的好处。
-
我真的无法想象没有什么你不能用其他容器做的。事实上,几乎所有其他容器都更快且功能更丰富。我认为 MEF 唯一的亮点在于处理插件架构,其中插件在不同的应用程序域中运行(就像 VS 一样)。
-
@DarinDimitrov:不行,因为我必须使用的库使用 MEF。所以这不是一个真正的解决方案。这可能是一个健康的建议,但我不能接受。无论如何,谢谢达林。
-
我非常了解这一点。这就是为什么我没有将其发布为答案。这更像是一种激励,您可以与您所在公司中负责做出这些设计决策的人交谈。谁知道呢,他们甚至可能会听你的:-)
-
AFAIK MEF 插件在同一个 AppDomain 中运行。如果 VS 插件在不同的 AppDomain 中运行,那么这不是 MEF 的功能。我认为 MAF 是做 AppDomain 分离的那个。
标签: asp.net-mvc dependency-injection mef constructor-injection