使用 2 个参数注入构造函数不起作用

Injecting into constructor with 2 params is not working

我有一个 ASP .Net Web API 控制器,我想使用 2 个参数。第一个是 EF 上下文,第二个是缓存接口。如果我只有 EF 上下文,则会调用构造函数,但是当我添加缓存接口时,我会收到错误消息:

An error occurred when trying to create a controller of type 'MyV1Controller'. Make sure that the controller has a parameterless public constructor.

private MyEntities dbContext;
private IAppCache cache;

public MyV1Controller(MyEntities ctx, IAppCache _cache)
{
     dbContext = ctx;
     cache = _cache;
}

我的UnityConfig.cs

public static void RegisterTypes(IUnityContainer container)
{
    // TODO: Register your types here
    container.RegisterType<MyEntities, MyEntities>();
    container.RegisterType<IAppCache, CachingService>();
}

我希望 Entity 现在知道这两种类型,当对 MyV1Controller 函数发出请求时,它应该能够实例化一个实例,因为该构造函数采用它知道的类型,但事实并非如此。知道为什么吗?

[编辑] 请注意,我创建了自己的 class (IConfig) 并将其注册并将其添加到构造函数中并且它起作用了,但是每当我尝试将 IAppCache 添加到我的构造函数并发出请求时API 我收到错误消息,告诉我它无法构建我的控制器 class。我看到的唯一区别是 IAppCache 不在我的项目命名空间中,因为它是第 3 方 class,但根据我的理解,这无关紧要。

这是 CachingService

的构造函数
public CachingService() : this(MemoryCache.Default) { } 

public CachingService(ObjectCache cache) { 
    if (cache == null) throw new ArgumentNullException(nameof(cache)); 
    ObjectCache = cache; 
    DefaultCacheDuration = 60*20; 
}

检查 IAppCache 实现 CachingService 以确保 class 在初始化时没有抛出任何异常。该无参数异常是在尝试创建控制器时发生错误时的默认消息。这不是一个非常有用的异常,因为它不能准确指出发生的真正错误是什么。

你提到它是第 3 方 interface/class。它可能正在请求容器不知道的依赖项。

引用 Unity Framework IoC with default constructor

Unity 使用最多的参数调用构造函数,在本例中是...

public CachingService(ObjectCache cache) { ... }

由于容器对ObjectCache一无所知,它将传入null,根据构造函数中的代码将抛出异常。

更新:

从评论中添加这个,因为它可以证明对其他人有用。

container.RegisterType<IAppCache, CachingService>(new InjectionConstructor(MemoryCache.Default));

参考此处Register Constructors and Parameters了解更多详情。

大多数 DI 容器在尝试解析类型时总是寻找具有最大参数数量的构造函数。这就是为什么默认调用 CachingService(ObjectCache cache) 构造函数的原因。由于ObjectCache实例没有注册到Unity,所以解析失败。一旦强制类型注册调用特定构造函数,一切正常。

因此,如果您注册 IAppCache 并强制它调用 CachingService() - 无参数构造函数,它将按预期工作。

container.RegisterType<IAppCache, CachingService>(new InjectionConstructor());

以这种方式注册,将强制调用无参数构造函数,并且在内部它将退回到第三方库想要用作默认值的任何内容。在你的情况下它将是

缓存服务() : 这个(MemoryCache.Default)

其他答案中提到的另一个选项是自己注册并传递构造函数参数。

container.RegisterType<IAppCache, CachingService>(new InjectionConstructor(MemoryCache.Default));

这也可行,但在这里您要负责提供缓存提供程序。在我看来,我宁愿让第三方库处理它自己的默认值,而不是让我作为消费者来承担这个责任。

请看How does Unity.Resolve know which constructor to use?

关于 Niject 的其他信息很少 https://github.com/ninject/ninject/wiki/Injection-Patterns

If no constructors have an [Inject] attribute, Ninject will select the one with the most parameters that Ninject understands how to resolve.

对于 LazyCache 版本 2.1.2(甚至更早),现有解决方案不再有效(没有接收 MemoryCache 的构造函数),但它的工作原理很简单:

container.RegisterType<IAppCache, CachingService>(new InjectionConstructor());

这适用于 .NET Framework 4.6.1、Unity Abstractions 3.1.0。