使用没有依赖项的绑定注入循环依赖项问题



我很难弄清楚为什么我会收到周期性依赖错误。我还得到了许多不同的激活路径和类调用,似乎是随机的。

这是一个已经工作了一年多的系统中的一个新问题。它一直在积极开发中,因此它不断变化并试图回滚更改以找出问题的确切位置,此时做起来有点太麻烦了。

似乎与多线程和竞争条件有关。当我添加更多正在运行的线程时,错误出现的频率更高。

我一直在努力弄清楚这一点,这时 Ninject 调用的激活路径/依赖项之一引起了我的注意。我列出的一个依赖项本身没有依赖项。

Ninject.ActivationException: Error activating IMetaValueProvider using binding from IMetaValueProvider to ExecutionOutputMetaValueProvider
A cyclical dependency was detected between the constructors of two services.
Activation path:
6) Injection of dependency IMetaValueProvider into parameter valueProviders of constructor of type MetaValueResolverFactory
5) Injection of dependency IMetaValueResolverFactory into parameter valueResolverFactory of constructor of type MessageExecutionContextFactory
4) Injection of dependency IMessageExecutionContextFactory into parameter executionContextFactory of constructor of type MessageProcessor
3) Injection of dependency IMessageProcessor into parameter messageProcessor of constructor of type MessageProcessingManager
2) Injection of dependency IMessageProcessingManager into parameter messageProcessingManager of constructor of type QueuePollerFactory
1) Request for QueuePollerFactory

在上面的例子中,ExecutionOutputMetaValueProvider绝对没有依赖关系。

以下是ExecutionOutputMetaValueProvider的来源

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DealerVision.Messaging
{
public class ExecutionOutputMetaValueProvider : IMetaValueProvider
{
public string MetaKeyPrefix
{
get
{
return "Output";
}
}
public object GetMetaValue(IMessageExecutionContext context, string key)
{
if(context.ExecutableMessage.Result == null)
{
throw new Exception($"{nameof(ExecutionOutputMetaValueProvider)} cannot get key "{key}" because the {nameof(ExecutableMessageBase)} does not have a result.");
}
if (context.ExecutableMessage.Result.ExecutionOutput.ContainsKey(key))
{
return context.ExecutableMessage.Result.ExecutionOutput[key];
}
return null;
}
public IEnumerable<string> GetPersistantKeys(IMessageExecutionContext executionContext)
{
if (executionContext.ExecutableMessage.Result == null)
return Enumerable.Empty<string>();
List<string> keys = new List<string>();
foreach (var kvp in executionContext.ExecutableMessage.Result.ExecutionOutput)
{
keys.Add($"{this.MetaKeyPrefix}.{kvp.Key}");
}
return keys;
}
}
}

两个问题:

  1. 如何准确判断周期性 2 依赖项是什么?Ninject 不会只列出循环中涉及的两个依赖项中的一个。
  2. 如果一个依赖项本身没有依赖项,那么该依赖项如何被视为循环的一部分。怎么可能有一个周期?

我显然错过了一些东西。任何帮助将不胜感激。

需要"自下而上"或"依赖优先"创建实例。这意味着,ExecutionOutputMetaValueProvider是在MessageExecutionContextFactory之前创建的,而再次是在之前创建的......QueuePollerFactory.

现在,ninject 确实在ExecutionOutputMetaValueProvider处停止,因为这会导致在链中更靠前创建类型。在这一点上,并没有确切说明那会是什么。

既然你说ExecutionOutputMetaValueProvider没有任何依赖项: .

  • 检查您是否错了:
    • 是否有多个构造函数?因为如果有一个构造函数带有 ninject 绑定的参数,它将使用这个,而不是没有参数的构造函数
    • 是否有属性或方法注入?另请参阅此处
    • 是否有具有相同名称的第二种类型 - 并且绑定实际上是针对另一种类型,而不是您期望的类型?(还要检查Rebind和条件绑定)。
  • 检查OnActivation的使用情况 - 这可能会导致激活与类型实例化耦合
  • 使用依赖关系创建扩展也可能导致不明显的激活

最新更新