注入带有2个参数的构造函数不起作用

时间:2016-11-21 19:20:11

标签: c# asp.net-web-api dependency-injection unity-container

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

  

尝试创建类型的控制器时发生错误   'MyV1Controller'。确保控制器有一个   无参数公共构造函数。

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函数发出请求时,它应该能够实例化一个实例,因为该构造函数接受它所知道的类型,但事实并非如此。知道为什么吗?

[编辑] 请注意,我创建了自己的类(IConfig)并将其注册并将其添加到构造函数中,但是每当我尝试将IAppCache添加到构造函数并向API发出请求时得到错误告诉我它无法构造我的控制器类。我看到的唯一区别是IAppCache不在我的项目名称空间中,因为它是第三方类,但这与我理解的内容无关。

以下是CachingService的构造函数

public CachingService() : this(MemoryCache.Default) { } 

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

3 个答案:

答案 0 :(得分:9)

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

你提到它是第三方界面/类。它可能是请求容器不知道的依赖关系。

引用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了解更多详情。

答案 1 :(得分:3)

尝试解析类型时,大多数DI容器始终会查找具有最大参数数量的构造函数。这就是默认情况下调用CachingService(ObjectCache缓存)构造函数的原因。由于ObjectCache实例未在Unity中注册,因此解析失败。一旦强制类型注册调用特定的构造函数,一切正常。

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

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

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

CachingService():this(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

  

如果没有构造函数具有[Inject]属性,Ninject将选择   Ninject了解如何解决的参数最多的一个。

答案 2 :(得分:0)

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

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

这适用于.NET Framework 4.6.1,Unity抽象3.1.0。