发生奇怪的事情:在我的 Web api 中,我在使用 Ninject 解析时将存储库注入到控制器中。存储库存储在私有只读成员变量中。工作完美!当调用 api 方法时,我访问该变量 - 结果发现它突然变成了 null!
伪示例:
public class MyController : ApiController {
private readonly IRepo _repo;
public MyController(IRepo repo) {
Guard.AgainstNullArgument("repo", repo); // guarding to
// make sure it's not null
// (would throw ex)
_repo = repo; <--- successfully injected
}
// calling this method
public HttpResponseMessage TestMethod() {
_repo.. <--- suddenly null
}
}
我已经将问题追溯到一个微小的细节:控制器中的方法之一(不是被访问的方法)用一个自定义属性进行注释,该属性指示 ninject 使用工作单元拦截该方法。如果我去掉该属性,一切都会神奇地再次起作用。
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Interface)]
public class UnitOfWorkAttribute : Attribute
{
}
public class EfUnitOfWorkInterceptor : SimpleInterceptor
{
private readonly IUnitOfWork _unitOfWork;
public EfUnitOfWorkInterceptor(IUnitOfWork unitOfWork)
{
Guard.AgainstNullArgument("unitOfWork", unitOfWork);
_unitOfWork = unitOfWork;
}
protected override void AfterInvoke(IInvocation invocation)
{
if(!_unitOfWork.Commited)
_unitOfWork.Commit();
_unitOfWork.Dispose();
}
}
编辑
我确实在各处都设置了断点来弄清楚发生了什么。在控制器上创建了一个析构函数,以确保整个类不会被垃圾化,并将只读成员更改为带有 getter/setter 的属性,我在 setter 上断点以检查它是否被分配了两次。根本没有发生任何可疑的事情。
编辑2
Ninject.Extensions.Interception.dll!Ninject.Extensions.Interception.Injection.Dynamic.DynamicMethodInjector.Invoke(object target = {EIT.Management.Configuration.Web.Api.Controllers.SetupGroupController}, object[] arguments = {object[2]}) Unbekannt
Ninject.Extensions.Interception.dll!Ninject.Extensions.Interception.Invocation.Invocation.CallTargetMethod() Unbekannt
编辑 3*
真实世界代码:http://pastebin.com/SqpR9KNR
真奇怪啊!我想也许你有另一个构造函数它没有设置你的_repo,然后是由它实例化的控制器的新实例。
如果您使用 LinFu(您应该这样做,因为 DynamicProxy 仍然需要无参数构造函数),解决方案非常简单:只需创建用
UnitOfWorkAttribute
virtual
注解的方法即可。
我通过一些测试发现了这一点:经过一些尝试,我注意到如果你删除
plan.Add(new ProxyDirective());
,一切都会起作用。当然,拦截器没有被应用,但这表明代理类是罪魁祸首。
Freds 的回答让我找到了我的问题,基本上是一个 DI 问题。 我有一个
BackgroundService
,它也实现了IHealthCheck
接口,配置:
services.AddHostedService<MyBackgroundServiceType>();
services.AddHealthChecks().AddCheck<MyBackgroundServiceType>();
基本上添加了两个
MyBackgroundServiceType
实例,其中第二个实例从未被 host.RunAsync()
调用,因此也从未被初始化 - 但它确实被调用进行健康检查,导致与原始海报相同的问题。
我将配置更改为:
services.AddSingleton<MyBackgroundServiceType>();
services.AddHostedService(x => x.GetRequiredService<MyBackgroundServiceType>());
services.AddHealthChecks().AddCheck<MyBackgroundServiceType>(typeof(MyBackgroundServiceType).Name);
一切都很好。