NInject и потокобезопасность - PullRequest
2 голосов
/ 31 мая 2010

У меня проблемы со следующим классом в многопоточной среде:

public class Foo
{
    [Inject]
    public IBar InjectedBar { get; set; }
    public bool NonInjectedProp { get; set; }

    public void DoSomething()
    {
        /* The following line is causing a null-reference exception */
        InjectedBar.DoSomething();
    }

    public Foo(bool nonInjectedProp)
    {
         /* This line should inject the InjectedBar property */
         KernelContainer.Inject(this);
         NonInjectedProp = nonInjectedProp;
    }
}

Это устаревший класс, поэтому я использую свойство, а не инъекцию в конструктор.

Иногда, когда DoSomething () вызывается, свойство InjectedBar имеет значение null. В однопоточном приложении все работает нормально.

Как это может происходить и как я могу предотвратить это?

Я использую NInject 2.0 без каких-либо расширений, хотя я скопировал KernelContainer из проекта NInject.Web.

Я заметил похожую проблему, возникающую в моих веб-сервисах. Эта проблема крайне непостоянна и ее трудно воспроизвести.

1 Ответ

2 голосов
/ 19 августа 2011

Прежде всего, позвольте мне сказать, что это неправильно на многих уровнях; KernelContainer был классом инфраструктуры, который хранился , в частности , чтобы обойти определенные ограничения в жизненном цикле страницы ASP.NET WebForms. Он никогда не предназначался для использования в коде приложения. Использование ядра Ninject (или любого контейнера DI) в качестве локатора службы является анти-паттерном .

Тем не менее, сам Ninject определенно ориентирован на многопоточность, поскольку он используется для постоянной обработки параллельных запросов в ASP.NET. Откуда бы ни исходил этот NullReferenceException, он имеет мало общего с Ninject.

Я могу представить две возможности:

  1. Вы должны инициализировать KernelContainer.Kernel где-нибудь, и , чтобы код мог иметь состояние гонки. Если что-то попытается использовать KernelContainer до полной инициализации ядра (возможно, если вы используете методы IKernel.Bind вместо загрузки модулей согласно руководству), вы получите такие ошибки. Или:

  2. Это ваша реализация IBar, которая имеет проблемы, и NullReferenceException происходит где-то внутри DoSomething метода. На самом деле вы не указываете, что InjectedBar равно null, когда вы получаете исключение, так что это законная возможность здесь.

Просто чтобы сузить поле возможностей, я бы сначала исключил KernelContainer. Если вам абсолютно необходимо использовать Ninject в качестве локатора службы из-за плохо спроектированной устаревшей архитектуры, то, по крайней мере, разрешите ему создавать зависимостей вместо того, чтобы полагаться на Inject(this). То есть любой класс или классы должны создать ваш Foo, иметь этот вызов класса kernel.Get<Foo>() и настроить ваше ядро ​​на Bind<Foo>().ToSelf().

...