题 私有成员在API方法调用时突然为null


奇怪的事情发生了:在我的web api中,我在使用Ninject解析时将一个存储库注入控制器。存储库存储在私有只读成员变量中。工作完美!当调用api方法时,我访问变量 - 只是为了看到它突然变为空!

伪示例:

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使用工作单元拦截方法。如果我把属性拿走,一切都神奇地再次起作用。

UnitOfWorkAttribute.cs

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Interface)]
public class UnitOfWorkAttribute : Attribute
{
}

AttributeInterceptionStrategy.cs(对于ninject)

http://pastebin.com/Qg6tQWye

StartupConfig.cs(组合根,IoC配置等)

http://pastebin.com/fcuSdujj

EfUnitOfWorkInterceptor.cs

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

编辑

我确实在任何地方都设置断点来弄清楚发生了什么。在控制器上做了一个析构函数,以确保整个类没有被破坏,并且还将readonly成员更改为具有getter / setter的属性,其中我在setter上断开指向以检查它是否被分配了两次。没有任何可疑的事情发生。

编辑2

http://pastebin.com/pQULHLT0

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


13
2018-01-06 16:14


起源


您是否尝试将断点添加到控制器的构造函数并检查调用堆栈?可能某些代码创建了另一个控制器而没有注入依赖... - Alexei Levenkov
在您的代码中放置断点我想知道您是否覆盖了值意义是否有触发回发的东西..?或者调用 Constructor 事件..您是否考虑过将其存储在Session变量中 - MethodMan
也许这只是您发布的代码中的一个错误,但它看起来不像您的构造函数应该编译。它有一个 repo 参数,但是你要保护一个不同的变量, unitOfWork 反对null。此外,您应该让操作使用null引用执行,然后捕获完整的堆栈跟踪以添加到您的问题中。我很好奇使用null控制器依赖的action方法的调用者是MVC或Ninject(或其他一些工具)。 - danludwig
有趣。使用UoW属性修饰的另一个操作方法,您是否也可以发布该代码?它是异步操作方法吗?当你调用它时,同一个readonly字段也是null吗? - danludwig
此外,尝试在控制器私有无参数构造函数中创建并在其上添加断点。还要创建一个静态列表(并在创建时将控制器的实例添加到此列表中)。为什么我要问它:可以在类型系统上做一些黑客攻击,比如忽略你的构造函数。 - Viktor Lova


答案:


这很奇怪!我想也许你有另一个构造函数 没有设置你的_repo,然后由该实例化的控制器的新实例。


1
2018-04-08 11:34





如果你使用LinFu(你应该使用它,因为DynamicProxy仍然需要一个无参数的构造函数),解决方案非常简单:只需使用带有注释的方法进行注释即可。 UnitOfWorkAttribute  virtual

我通过一些测试发现了这一点:经过一些尝试,我注意到如果你只是删除,一切都有效 plan.Add(new ProxyDirective());。当然,拦截器没有应用,但这指出了代理类是应该受到责备的事实。


0
2018-01-31 21:46