【问题标题】:Injecting into constructor with 2 params is not working使用 2 个参数注入构造函数不起作用
【发布时间】:2017-04-05 07:06:03
【问题描述】:

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

尝试创建类型控制器时出错 'MyV1 控制器'。确保控制器具有 无参数的公共构造函数。

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>();
}

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

[编辑] 请注意,我创建了自己的类 (IConfig) 并将其注册并将其添加到构造函数中并且它可以工作,但是每当我尝试将 IAppCache 添加到我的构造函数并向 API 发出请求时,我都会收到错误消息我它不能构造我的控制器类。我看到的唯一区别是 IAppCache 不在我的项目命名空间中,因为它是第 3 方类,但据我了解这并不重要。

这是 CachingService 的构造函数

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

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

【问题讨论】:

  • 类注册是单例吗?还要检查IAppCacheimplementation CachingService 以确保该类在初始化时没有抛出任何异常。当尝试创建控制器时发生错误时,该无参数异常是默认消息。
  • CachingService 的依赖关系是什么你提到它是一个 3rd 方接口/类。它可能正在请求容器不知道的依赖项。
  • 只需在控制器中创建无参数构造函数,例如。公共 MyV1Controller() { }

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


【解决方案1】:

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

您提到它是第 3 方接口/类。它可能正在请求容器不知道的依赖项。

引用Unity Framework IoC with default constructor

Unity 正在调用具有最多参数的构造函数,在这种情况下是......

public CachingService(ObjectCache cache) { ... }

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

更新:

从 cmets 添加它,因为它可以证明对其他人有用。

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

更多详情请参考Register Constructors and Parameters

【讨论】:

  • 这是实现: public CachingService() : this(MemoryCache.Default) { } public CachingService(ObjectCache cache) { if (cache == null) throw new ArgumentNullException(nameof(cache));对象缓存 = 缓存; DefaultCacheDuration = 60*20; }
  • 那么我猜cache==nulltrue
  • 如果我在 UnityConfig:RegisterTypes() 中创建 CachingService() 的实例,它不为空,因此不明白为什么在应用程序生命的后期创建我的控制器时它会为空。无论如何,在 Unity 为控制器 ctor 进行这些对象创建以获得更好的外观时,它是否可以连接到 Unity?
  • 我刚刚做了以下操作,它奏效了! container.RegisterType(new InjectionConstructor(MemoryCache.Default));仍然不确定为什么 Unity 不尝试使用无参数 ctor
  • 你所做的是正确的。在我有机会回应之前你就想通了。 still not sure why Unity wasn't trying to use the parameterless ctor - 这就是它的设计方式。它是大多数 IoC 容器的标准配置。
【解决方案2】:

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

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

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

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

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 理解如何解析的参数最多的一个。

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

      猜你喜欢
      • 2015-11-11
      • 2012-05-01
      • 2016-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-27
      相关资源
      最近更新 更多