Question

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.

Was it helpful?

Solution

Incase you are using Ninject.Web.WebApi.WebHost then InSingletonScope will give you a single instance in a threadsafe manner.

But unfortunately there are many blog posts and stackoverflow answers that show incorrectly implemented DependencyResolver implementations using an ActivationBlock that will give you an object in request scope even though they are registered as singletons.

What Ninject doesn't do is to ensure that the returned objects are thread safe themselves. It seems this is that case in your case. The internal structure of a Dictionary is not thread safe. Just one thread is allowed to modify a dictionary at the same time. You should switch to a ConcurrentDictionary.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top