Нулевая ссылка в вызове web api

Это странно, и я не могу понять, что здесь происходит. У меня есть проект веб-API, который в одном контроллере вызов определенного метода в конечном итоге вызывает функцию в службе, которая выглядит следующим образом:

    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;
        }
    }

cache это просто словарь:

 protected Dictionary<Guid, MyClassBase> cache { get; set; }

Это создается в конструкторе для этого класса:

 cache = new Dictionary<Guid, MyClassBase>();

Это прекрасно работает в 99,9% случаев, но иногда, при первом запуске приложения, первый запросNullReferenceException - и странная часть, он утверждает, что источником является эта строка:

cache[id] = param;

Но дело в том, еслиcache является нулевым (что не может быть, это было установлено в конструкторе, это личное, и этотолько метод, который даже затрагивает это), тогда это должно было бы бросить в:

if (cache.ContainsKey(id))

и еслиid был бы нулевым, тогда я получил бы неправильный запрос от API, потому что это не сопоставило бы, плюс мой оператор linq, чтобы получить тип с соответствующимGUID возвратил бы нуль, который я также проверяю. И еслиparam является нулевым, это не должно иметь значения, вы можете установить словарную запись в нулевое значение.

Это похоже на состояние гонки с чем-то, что не полностью инициализировано, но я не вижу, откуда оно исходит или как защититься от него.

Вот пример того, что он (иногда) выдает (как JSON, потому что веб-интерфейс возвращает json, и я получил его, выплевывая мне сообщения об ошибках, чтобы я мог их найти):

{
    "message": "An error has occurred.",
    "exceptionMessage": "Object reference not set to an instance of an object.",
    "exceptionType": "System.NullReferenceException",
    "stackTrace": "   at System.Collections.Generic.Dictionary`2.Insert(TKey key, 
        TValue value, Boolean add)\r\n   at 
        System.Collections.Generic.Dictionary`2.set_Item(TKey key, TValue value)\r\n   
        at MyNameSpace.Services.MyFinderService.GetThing(Guid id) in
        c:\\...\\MyFinderService.cs:line 85\r\n   
        at MyNameSpace.Controllers.MyController.GetMyParameters(Guid id) in 
        c:\\...\\Controllers\\MyController.cs:line 28\r\n   at 
        lambda_method(Closure , Object , Object[] )\r\n   at
        System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass13.
        <GetExecutor>b__c(Object instance, Object[] methodParameters)\r\n   at
        System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance,
        Object[] arguments)\r\n   at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.
        <>c__DisplayClass5.<ExecuteAsync>b__4()\r\n   at
        System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken
        cancellationToken)"
}

line 85 это линия, которую я выделил выше.

Это своего родагейзенбаг, но мне просто удалось заставить его бросить, выполнив это немедленно на моей html-странице (конечно, делая это во второй раз, это работало просто отлично):

    $.ajax({
        url: "@Url.Content("~/api/MyController/GetMyParameters")",
    data: { id: '124c5a71-65b7-4abd-97c0-f5a7cf1c4150' },
    type: "GET"
    }).done(function () { console.log("done"); }).fail(function () { console.log("failed") });

    $.ajax({
        url: "@Url.Content("~/api/MyController/GetMyParameters")",
        data: { id: '7cc9d80c-e7c7-4205-9b0d-4e6cb8adbb57' },
    type: "GET"
    }).done(function () { console.log("done"); }).fail(function () { console.log("failed") });

    $.ajax({
        url: "@Url.Content("~/api/MyController/GetMyParameters")",
        data: { id: '1ea79444-5fae-429c-aabd-2075d95a1032' },
    type: "GET"
    }).done(function () { console.log("done"); }).fail(function () { console.log("failed") });

    $.ajax({
        url: "@Url.Content("~/api/MyController/GetMyParameters")",
        data: { id: 'cede07f3-4180-44fe-843b-f0132e3ccebe' },
    type: "GET"
    }).done(function() { console.log("done"); }).fail(function() { console.log("failed")});

Быстро выполнив четыре запроса, два из них потерпели неудачу в одной и той же точке, но вот где это действительно приводит в бешенство, оно прерывается на этой линии, и я могу наводить курсорcache, id а такжеparam в Visual Studio и увидеть их текущее значение иникто из них нулевые! И в каждом случаеcache имеетCount из 1, что также странно, поскольку предполагается, что это синглтон, созданный Ninject, поэтому я начинаю подозревать, что с Ninject что-то пошло не так.

Для справки, в NinjectWebCommon я регистрирую этот сервис следующим образом:

kernel.Bind<Services.IMyFinderService>().To<Services.MyFinderService>().InSingletonScope();

Заметка: Я тоже это опубликовалСинглтоны и условия гонки потому что я не уверен на 100%, что проблема не в Ninject, но я не хотел путать этот вопрос со слишком большим количеством догадок о том, чтоможет быть быть причиной.

Ответы на вопрос(1)

Ваш ответ на вопрос