Related to this question:
Null reference in web api call
But I'm spawning this off separately because it I think it might really be an issue with Ninject and I don't want to confuse the original question in case I'm wrong about this.
My problem is that I have a web api project that uses Ninject to manage dependency injection and most of the time it works fine. The problem is if you fire off multiple request very quickly right after starting the application, sometimes they fail in some really weird way with NullReferenceExceptions
that simply shouldn't exist for objects that don't appear to be null and I'm wondering if it's an issue with Ninject using InSingletonScope
and not really giving me a singleton but sometimes giving me something that hasn't finished initializing (but perhaps is initialized by the time I look at it in the debugger). Is that possible? Or am I completely barking up the wrong tree?
I have Ninject set up using Nuget packages and some web resources (sorry I don't seem to have the link to exactly which ones) and I thought I was doing it right. I have references in my project to Ninject
and Ninject.Web.Common
. In NinjectWebCommon.cs
I have this for registering a bunch of services (I've excluded most of them, to isolate just the one that is giving me trouble):
private static void RegisterServices(IKernel kernel)
{
System.Diagnostics.Debug.WriteLine("Registering Services...");
kernel.Bind<Services.IUserService>().To<Services.UserService>().InSingletonScope();
kernel.Bind<Services.IMyFinderService>().To<Services.MyFinderService>().InSingletonScope();
//kernel.SingletonBind<Services.IMyFinderService>().To<Services.MyFinderService>();
//kernel.Bind<Services.IMyFinderService>().ToConstant<Services.MyFinderService>(new Services.MyFinderService(kernel.Get<Services.IUserService>()));
}
The MyFinderService
is the one giving me trouble and note that it's constructor take an IUserService
which was registered before it (and may also be the cause of the problem):
public MyFinderService(IUserService service)
{
cache = new Dictionary<Guid, MyClassBase>();
userService = service;
}
I tried a couple of different approaches for how to bind it (the second one was suggested in an answer to this question: Ninject InSingletonScope with Web Api RC) but it still seems something isn't right when my API controller calls this method on MyFinderService
:
public MyClassBase GetThing(Guid id)
{
if (cache.ContainsKey(id))
{
return cache[id];
}
else
{
var type = typeof(MyClassBase).Assembly.GetTypes().FirstOrDefault
(
t => t.IsClass &&
t.Namespace == typeof(MyClassBase).Namespace + ".Foo" &&
t.IsSubclassOf(typeof(MyClassBase)) &&
(t.GetCustomAttribute<MyIdAttribute>()).GUID == id
);
if (type != null)
{
System.Diagnostics.Debug.WriteLine(string.Format("Cache null: {0}",cache == null));
var param = (MyClassBase)Activator.CreateInstance(type, userService);
cache[id] = param;
return param;
}
return null;
}
}
I sometimes get a NullReferenceException
on this line:
cache[id] = param;
Even though in the debugger cache
, id
and param
all appear to have values.
It was my assumption that when I registered something as a singleton that Ninject would handle all the details of making sure it really is a singleton and locking access during lazy initialization to ensure that it doesn't create a separate one, but maybe I'm wrong about that?
So how can I safely create and register a single instance of my class in the context of a web api project that might get multiple request coming from different threads.