【问题标题】:Ninject - Binding.GetProvider throws NullReferenceExceptionNinject - Binding.GetProvider 抛出 NullReferenceException
【发布时间】:2012-11-20 14:51:33
【问题描述】:

我在一个 asp.net Web 表单应用程序中使用 2.2.0.0 版的 Ninject,经过几百次请求后,它有时会在 Binding 类的 GetProvider 方法中引发 NullReferenceException。

示例堆栈跟踪:http://pastebin.com/BbhsPQMT

仅当我对应用程序进行压力测试并且异常的来源通常不同(解析不同的接口)时才会发生异常。

为了试图理解为什么会出现这个问题,我查看了 Ninject 源代码并插入了一些代码行以进行调试。后来确认为null的对象是Binding类中的ProviderCallback属性。

我还在 ProviderCallback 属性的 set 运算符中添加了一些代码,以便了解它是否被设置为 null。在运行了一些测试并查看了一些内存转储之后,似乎 ProviderCallback 属性没有被设置为空值,所以我认为实例正在被 GC 收集。

我还是不明白为什么会这样……

非常感谢任何帮助。

编辑:我们升级到最新版本的 Ninject 只是为了检查异常是否仍然发生,但在对应用程序进行压力测试后我们得到了同样的异常:http://pastebin.com/YaiaZndz

【问题讨论】:

  • 你应该报告这个。 NullReferenceException 始终表示引发它的代码中的错误。
  • 尝试更新到最新的 Ninject 版本。

标签: c# asp.net exception dependency-injection ninject


【解决方案1】:

我无法告诉您此问题的原因,因为我无法重现这种行为。但是,您可以采取一些步骤来确定问题。

正如您所说,问题是由ProviderCallback 引起的,即null。这不能由 GC 引起,因为 GC 永远不会将 null 分配给属性。相反,您将得到一个已经处理的异常或其他奇怪的行为。但是还有其他一些原因会发生这种情况:

  1. Null 是在某个时间分配的,但既然您已经验证过,这不是原因。
  2. 根本没有分配。
  3. 稍后会创建一个新的BindingConfiguration

可以通过在BindingConfiguration 构造函数中添加断点轻松验证第三点。在成功配置内核并开始解析对象后,不应再调用它。

对于第二个问题,在内核配置后执行以下操作:

var kernel = your fully configured kernel;
var bindingsField = typeof(KernelBase).GetField("bindings", BindingFlags.NonPublic | BindingFlags.Instance);
var bindings = bindingsField.GetValue(kernel) as IEnumerable<KeyValuePair<Type, ICollection<IBinding>>>;

foreach (var bindingsEntry in bindings
    .Where(bindingsEntry => bindingsEntry.Value
        .Any(binding => binding.BindingConfiguration.ProviderCallback == null)))
{
    throw new Exception(string.Format("No Provider callback defined for {0}.", bindingsEntry.Key));
}

【讨论】:

  • 嗨雷莫。很抱歉回复晚了,但我想看看你提供的任何条件是否属实。第 2 次和第 3 次都没有发生。事实证明,这很难重现,因为对 aspx 页面的每一百个请求只会发生一次。我看到的一件奇怪的事情是内存转储中的第二个 StandardKernel,但我无法弄清楚它是在哪里创建的(!refs 和 !gcroot 只返回了一个巨大的对象数组的根,这些对象似乎是appdomain - 我还是不明白为什么)。
  • 在Kernel的构造函数中添加断点,就不能知道它是在哪里创建的吗?
  • Remo,我找到了创建它的原因。在 Ninject 的第 3 版中,现在有一个对 Ninject.Web 命名空间的依赖关系,它在 Ninject.Web.KernelContainer 中创建了一个 StandardKernel 隐含性。我现在回到我原来的问题。我不知道下一步该往哪里看。让我告诉你,我们还会收到一些罕见的 ActivationExceptions,一旦开始发生它们就会继续抛出,直到我们重新启动应用程序池。我认为这个问题可能是相关的。这发生在版本 2.2 中,我还能够在版本 3 中获得罕见的 ActivationExceptions(在数百个请求之后)
  • 所以目前的状态是: 1. No ProviderCallback 最初为空。 2. 后面没有创建新的BindingConfiguration。 3. 后面没有给 ProviderCallback 赋值。 4. 只使用一个内核。在那种情况下,我不明白这怎么会发生。你能创建一个精简的解决方案来演示这个问题吗?
  • @TiagoMargalho 感谢您的调查。我强烈建议不要在第一次解析对象后进行任何绑定或重新绑定,因为即使解决了多线程问题,结果也是不可预测的。例如。如果对象的范围不是瞬态的,您仍然可以获得先前实现的实例。尝试使用 RRR - 模式:blog.ploeh.dk/2010/09/29/TheRegisterResolveReleasePattern.aspx
猜你喜欢
  • 2011-02-04
  • 2013-05-30
  • 2020-11-17
  • 2016-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多