NInject and thread-safety
I am having problems with the following class in a multi-threaded environment:
public class Foo
{
[Inject]
public IBar InjectedBar { get; set; }
public bool NonInjectedProp { get; set; }
public void DoSometh开发者_运维知识库ing()
{
/* 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;
}
}
This is a legacy class which is why I am using property rather than constructor injection.
Sometime when the DoSomething() is called the InjectedBar property is null. In a single-threaded application, everything runs fine.
How can this be occuring and how can I prevent it?
I am using NInject 2.0 without any extensions, although I have copied the KernelContainer from the NInject.Web project.
I have noticed a similar problem occurring in my web services. This problem is extremely intermittent and difficult to replicate.
First of all, let me say that this is wrong on so many levels; the KernelContainer
was an infrastructure class kept specifically to work around certain limitations in the ASP.NET WebForms page lifecycle. It was never meant to be used in application code. Using the Ninject kernel (or any DI container) as a service locator is an anti-pattern.
That being said, Ninject itself is definitely thread-safe because it's used to service parallel requests in ASP.NET all the time. Wherever this NullReferenceException
is coming from, it's got little if anything to do with Ninject.
I can think of two possibilities:
You have to initialize
KernelContainer.Kernel
somewhere, and that code might have a race condition. If something tries to use theKernelContainer
before the kernel is fully initialized (possible if you use theIKernel.Bind
methods instead of loading modules as per the guidance), you'll get errors like this. Or:It's your
IBar
implementation itself that has problems, and theNullReferenceException
is happening somewhere inside theDoSomething
method. You don't actually specify thatInjectedBar
isnull
when you get the exception, so that's a legitimate possibility here.
Just to narrow the field of possibilities, I'd eliminate the KernelContainer
first. If you absolutely must use Ninject as a service locator due to a poorly-designed legacy architecture, then at least allow it to create the dependencies instead of relying on Inject(this)
. That is to say, whichever class or classes need to create your Foo
, have that class call kernel.Get<Foo>()
, and set up your kernel to Bind<Foo>().ToSelf()
.
精彩评论