C# 强制IKernel.Inject()在调用线程上进行注入?

C# 强制IKernel.Inject()在调用线程上进行注入?,c#,asp.net-web-api,dependency-injection,ninject,C#,Asp.net Web Api,Dependency Injection,Ninject,我正在使用ASP.NET创建一个RESTAPI,我正在使用Ninject作为Web API过滤器的依赖项注入程序。不幸的是,在使用IKernel接口的Inject()方法时,我似乎遇到了竞争条件 这里是我的一个过滤器的简化版本,它执行HTTP基本身份验证 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true)] public class BasicAuthenticationAttri

我正在使用ASP.NET创建一个RESTAPI,我正在使用Ninject作为Web API过滤器的依赖项注入程序。不幸的是,在使用IKernel接口的Inject()方法时,我似乎遇到了竞争条件

这里是我的一个过滤器的简化版本,它执行HTTP基本身份验证

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true)]
public class BasicAuthenticationAttribute : AuthorizationFilterAttribute
{
    private IAccountService accountService;

    [Inject]
    public IAccountService AccountService
    {
        get { return accountService; }
        set
        {
            Debug.WriteLine("set_AccountService called in thread {0}", Thread.CurrentThread.ManagedThreadId);
            accountService = value; 
        }
    }

    public override void OnAuthorization(...)
    {
        // Use the injected IAccountService here...
    }
}
这是我的IFilterProvider实现,它使用Ninject初始化我的过滤器

public class NinjectFilterProvider : ActionDescriptorFilterProvider, IFilterProvider
{
    private readonly IKernel kernel;

    public NinjectFilterProvider(IKernel kernel)
    {
        if (kernel == null) throw new ArgumentNullException("kernel");
        this.kernel = kernel;
    }

    public new IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
    {
        var filters = base.GetFilters(configuration, actionDescriptor);

        foreach (var filter in filters)
        {
            // For demonstration purposes, I removed all but one of my filters.
            var inst = (BasicAuthenticationAttribute)filter.Instance;
            Debug.WriteLine("kernel.Inject() will be called in thread {0}", Thread.CurrentThread.ManagedThreadId);
            kernel.Inject(inst);
            if (inst.AccountService == null)
            {
                // This Sleep() call demonstrates the problem.
                Thread.Sleep(500);
                Debug.WriteLine("Before wait inst.AccountService == null: true, afterword inst.AccountService == null: {0} on thread {1}", inst.AccountService == null, Thread.CurrentThread.ManagedThreadId);
            }
            Debug.WriteLine("inst.AccountService == null: {0} on thread {1}", inst.AccountService == null, Thread.CurrentThread.ManagedThreadId);
            Debug.WriteLine("kernel.Inject() was called in thread {0}", Thread.CurrentThread.ManagedThreadId);
        }

        return filters;
    }
}
您可以看到,在线程6上调用kernel.Inject()之后,inst.AccountService仍然为null,并且只有在当前线程休眠半秒钟后,才会分配它。这意味着Ninject必须在不同的线程上解析和分配依赖项。有没有办法强迫Ninject在调用kernel.Inject()的同一线程上执行所有这些操作?在我的代码中不欢迎种族条件

编辑:


替换行
kernel.Inject(inst)使用
inst.AccountService=kernel.Get()
修复了这个问题,因此在不同线程上设置依赖关系的奇怪行为肯定源自Inject()调用。如果无法以我想要的方式配置Ninject,那么我的选项似乎是使用我自己的基于反射的注入替换或使用不同的DI库。

我认为问题可能与以下事实有关:由于web api的异步性质,线程和请求之间不一定存在关联。我也有类似的问题,最后花了很多时间在InRequestScope:。无论您是否使用owin,关于RequestScope的概念可能仍然是相关的。不确定这是否是答案,因此只是一个注释。我使用的是InRequestScope,但我只是将所有这些绑定都更改为使用InTransientScope,并且出现了相同的错误,因此很遗憾,我认为这与范围没有直接关系。我同意这可能与异步请求有关,诀窍在于找出到底哪里出了问题。注意:我的api控制器操作都不是C#关键字意义上的
async
kernel.Inject() will be called in thread 7
kernel.Inject() will be called in thread 8
kernel.Inject() will be called in thread 6
set_AccountService called in thread 7
set_AccountService called in thread 8
inst.AccountService == null: False on thread 7
inst.AccountService == null: False on thread 8
kernel.Inject() was called in thread 7
kernel.Inject() was called in thread 8
Before wait inst.AccountService == null: true, afterword inst.AccountService == null: False on thread 6
inst.AccountService == null: False on thread 6
kernel.Inject() was called in thread 6