0

Stack Trace

System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
   at Mobile.DataStructures.Caching.Cache`2.Add(TKey key, TValue value, Func`1 autoRefresh, TimeSpan timeToExpire) in C:\Project\Caching\Cache.cs:line 68
   at Mobile.DataStructures.Caching.Cache`2.Add(TKey key, TValue value, Func`1 autoRefresh) in C:\Project\Caching\Cache.cs:line 51
   at Mobile.Authentication.Principal.PrincipalExtensions.AddUserPermissionsToCache(String username) in C:\Project\Helpers\Auth\PrincipalExtensions.cs:line 53
   at Mobile.Authentication.Principal.PrincipalExtensions.RetrieveUserPermissions(PrincipalWithActivities principal, String username) in C:\Project\Helpers\Auth\PrincipalExtensions.cs:line 37
   at Mobile.MvcApplication.Application_PostAuthenticateRequest(Object sender, EventArgs e) in C:\Project\Global.asax.cs:line 126

Cache.cs

public class Cache<TKey, TValue>
{
    private static readonly IDictionary<TKey, CacheItem<TValue>> _Cache = new Dictionary<TKey, CacheItem<TValue>>();

    ...

    /// <summary>
    /// Adds the item to the cache where it will use the indicated autoRefresh function to refresh the value when expired.
    /// Will set the time to expire to the indicated time.
    /// </summary>
    public void Add(TKey key, TValue value, Func<TValue> autoRefresh, TimeSpan timeToExpire)
    {
        var item = new CacheItem<TValue>()
        {
            Value = value,
            RefreshCache = autoRefresh,
            CachedOn = DateTime.Now,
            TimeToExpire = timeToExpire
        };

        _Cache.Add(key, item); // NULL-REFERENCE EXCEPTION: This line threw the NullReferenceException.
        TriggerChanged(new CacheEventArgs<TKey, TValue>(key, null, item));

        // REFRESH: If the value is already null or default refresh it immediately.
        if (item.Value == null || item.Value.Equals(default(TValue)))
        {
            var before = new CacheItem<TValue>(item);
            item.Value = item.RefreshCache();
            TriggerRefreshed(new CacheEventArgs<TKey, TValue>(key, before, item));
        }
    }
}

Enivornment & Other Details

This is part of an ASP.NET MVC 5 project and the top of the execution chain is the Application_PostAuthenticateRequest(object sender, EventArgs e) event in the global.asax file.

I've only experienced this immediately after deploying to the server; however, I feel like this should be able to happen at all. Shouldn't the static variable be initialized by that point?

Question

It is static, readonly, and it has a static initializer. How did the line _Cache.Add(key, item); throw a NullReferenceException?

Shelby115
  • 2,816
  • 3
  • 36
  • 52
  • From your code it´s *impossible* that the exception is thrown at that line. Are ylu sure that this is your actual code? In particular please provide a [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve) – MakePeaceGreatAgain May 03 '18 at 19:06
  • Absolutely certain. Haven't changed this code for weeks and it threw that exception the last time I deployed. Like I said, it has only happened immediately after deploying, but it's baffling to me how. – Shelby115 May 03 '18 at 19:07
  • 1
    Can happen if you are calling Add from multiple threads without proper synchronization (and I don't see any locks here). – Evk May 03 '18 at 19:08
  • @Evk This is sounding like a possibility. How would I avoid this? I assume it has something to do with `lock` but I don't know enough of the subject. Point me in the right direction? – Shelby115 May 03 '18 at 19:10
  • Hard to describe in comment, but in two words - either lock around every access to _Cache, or use appropriate collection, like ConcurrentDictionary. – Evk May 03 '18 at 19:13
  • @Evk Is it really as simple as changing it to `private static readonly IDictionary> _Cache = new ConcurrentDictionary>();` because that seems too easy haha. (If that's the case post that as the answer and I'll accept it. Multithreading has to be the reason for the null-reference because in a single thread environment I think it's reasonable to say this exception is impossible). – Shelby115 May 03 '18 at 19:14
  • No it's not that easy unfortunately :) But it will most likely "fix" this exception. Though you still need to familiarize yourself with how to write good thread safe code. – Evk May 03 '18 at 19:17

0 Answers0