【问题标题】:Asp.net MVC base controller with constructor injection and MEF带有构造函数注入和 MEF 的 Asp.net MVC 基本控制器
【发布时间】: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 来实例化控制器。

总结一下:

  1. 我有一个基本的抽象控制器类,它有自己的依赖项
  2. 我有后代控制器使用导入来获取由 MEF 注入的参数(即它们的依赖项以及基类的依赖项)
  3. 单元测试不使用 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


【解决方案1】:

这可能与线程有关,因为默认情况下 MEF 容器不是线程安全的。在容器的构造函数中,尝试启用线程安全:

var container = new CompositionContainer(catalog, true);

【讨论】:

  • 我可以在库中看到我必须使用的语句。它使用false 表示isThreadSafe。那我现在能做什么呢?
  • 您不能重新编译库并将isThreadSafe 设置为true 吗?如果没有,我会向图书馆作者提出这个问题。
猜你喜欢
  • 1970-01-01
  • 2011-01-01
  • 1970-01-01
  • 2011-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多