2011-04-28 94 views
7

我有一段代码在要处理的项目列表上运行Parallel.Foreach。每次迭代都创建一对对象,每个对象都实例化并处理它自己的Ninject IKernel实例。 IKernel在对象完成工作时处理。Parallel.Foreach中的Ninject异常

这就是说,这段代码在我的Windows 7,I7笔记本电脑上工作得非常好。但是,当我将它推送到运行Windows 2008的VPS时,我得到这个异常。异常不会在同一次迭代中发生,有时会经历10次迭代并抛出异常,有时会经历数百次异常。显然,它似乎是一个线程问题,但它不会发生在我的VPS以外的任何地方。如果它很重要,则将在ASP.NET IIS中进行托管。

System.AggregateException: One or more errors occurred. ---> 
System.ArgumentOutOfRangeException: Index was out of range. 
    Must be non-negative and less than the size of the collection. 
    Parameter name: index 
     at System.Collections.Generic.List`1.RemoveAt(Int32 index) 
     at Ninject.KernelBase.Dispose(Boolean disposing) 

下面是代码片段:

//Code that creates and disposes the Ninject kernel 
using(ninjectInstance = new NinjectInstance()) 
{ 
    using (var unitOfWork = ninjectInstance.Kernel.Get<NinjectUnitOfWork>()) 
    { 
     Init(); 
     continueValidation = Validate(tran, ofr); 
    } 
} 

public class NinjectInstance : IDisposable 
{ 
    public IKernel Kernel { get; private set; } 

    public NinjectInstance() 
    {   
     Kernel = new StandardKernel(
      new NinjectSettings() { AllowNullInjection = true }, 
      new NinjectUnitOfWorkConfigModule());   
    } 

    public void Dispose() 
    { 
     if (Kernel != null) 
     { 
      Kernel.Dispose(); 
     } 
    } 
} 

编辑1 有一两件事是肯定的,这是一个线程安全的问题,我不应该创建的多个实例IKernel每个应用程序。对于如何配置合适的作用域来完成实体框架上下文线程安全性,仍然保留UoW类型的方法,其中多个业务层类可以在单个线程中在UoW范围内共享相同的EF上下文,这是一个理解问题。

回答

5

http://groups.google.com/group/ninject/browse_thread/thread/574cd317d609e764

正如我告诉你Ninject的构造函数是不是线程安全的ATM,除非你正在使用NOWEB!如果多次创建/部署内核,您将不得不自己同步访问权限!我仍然建议重新设计你的UoW实现!

+0

谢谢雷莫,与你一起在谷歌用户组关于此。只要我明白它是什么,我会在这里更新正确的答案。 – e36M3 2011-04-29 12:21:40

-1

看起来好像ninjectInstance是一个实例变量。因此,它可能是在并行环境,ninjectInstance.Dispose()会被调用两次(主叫Kernel.Dispose()不内核属性设置为)为同一实例,因为Kernel.Dispose()已经被调用,该方法失败。

也许你想要的东西,像

using (var ninjectInstance = new NinjectInstance()) { 
.. 
} 
+1

我不认为这是可能的,因为只有一个线程(处理特定的Parallel.Foreach迭代的线程)创建具有类级别ninjectInstance的对象,然后在“using”语句中使用该对象。只要下一次迭代发生,该对象已经超出范围,下一次迭代将创建它自己的集合。它是一个实例变量和类范围的原因是因为它允许从此对象继承的类在Init()和Validate()方法中轻松使用base.ninjectInstance.Get <>。没有我必须将它作为参数传递。 – e36M3 2011-04-28 15:27:49

+0

顺便说一句,为了安全我在Kernel.Dispose()之后设置了Kernel = null,同样的问题。 – e36M3 2011-04-28 16:09:43

+0

-1虽然你只是试图有帮助,这与潜在的问题没有关系,并没有添加任何事实的辩论,对不起...... – 2011-04-29 08:04:39