I am having a very strange behaviour as in this picture:
As you can see in the Watch window, everything that can be possibly null
are not null
.
Here is the full code of the function:
public LogInTokenCache GetUserIdFromToken(string token)
{
LogInTokenCache item = null;
if (this.TokenCache.ContainsKey(token))
{
item = this.TokenCache[token];
if (item.ExpirationTime < DateTime.Now)
{
this.TokenCache.Remove(item.Token);
return null;
}
}
else
{
LogInTokenBusiness tokenBusiness = new LogInTokenBusiness();
var entity = tokenBusiness.FindToken(token);
if (entity != null && entity.Token != null)
{
item = new LogInTokenCache()
{
Token = entity.Token,
UserID = entity.UserId,
ExpirationTime = entity.ExpirationTime,
};
this.TokenCache.Add(item.Token, item);
}
}
return item;
}
I used Find All References feature, and this is the only where I use the Constructor as well as a declaration (I use it for entire Web App):
public class IdentityController : Controller
{
private static EmailAdpater EmailAdapter = new EmailAdpater();
private static UserIdentityTokenShortener TokenShortener = new UserIdentityTokenShortener();
public static LoginTokenManager LoginTokenManager = new LoginTokenManager();
...
Has anyone encountered this problem? What did I do wrong?
EDIT: Added StackTrace and Details EDIT2: Edited title so future people can search this topic in case they have the same problem.
at System.Collections.Generic.Dictionary12.Insert(TKey key, TValue value, Boolean add)
at System.Collections.Generic.Dictionary12.Add(TKey key, TValue value)
at MobileDatingAPI.Models.LoginTokenManager.GetUserIdFromToken(String token) in d:\FPT University\Capstone 2\TFSRepo\Projects\MobileDatingAPI\MobileDatingAPI\Models\LoginTokenManager.cs:line 48
at MobileDatingAPI.Models.Utils.GetUserFromTokenID(Controller controller, String token, BaseApiViewModels model) in d:\FPT University\Capstone 2\TFSRepo\Projects\MobileDatingAPI\MobileDatingAPI\Models\Utils\Utils.cs:line 68
at MobileDatingAPI.Controllers.CommunityController.UpdateActivity(String token, Nullable11 longitude, Nullable11 latitude) in d:\FPTUniversity\Capstone 2\TFSRepo\Projects\MobileDatingAPI\MobileDatingAPI\Controllers\CommunityController.cs:line 84
at lambda_method(Closure , ControllerBase , Object[] )
at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary12 parameters)
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary12 parameters)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.ActionInvocation.InvokeSynchronousActionMethod()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<BeginInvokeSynchronousActionMethod>b__39(IAsyncResult asyncResult, ActionInvocation innerInvokeState)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult12.CallEndDelegate(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResultBase`1.End()
at System.Web.Mvc.Async.AsyncResultWrapper.End[TResult](IAsyncResult asyncResult, Object tag)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3d()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.AsyncInvocationWithFilters.<>c__DisplayClass46.<InvokeActionMethodFilterAsynchronouslyRecursive>b__3f()
I use Multi-Threading
This is almost certainly the problem then: since everything in your code is null
-checked and/or created with values that are non-null
, the only place where the problem could happen is the implementation of Dictionary
.
When the capacity of the dictionary is reached, the collection re-allocates its internal data structures. If one thread catches the dictionary in the middle of reallocation performed by another thread, some of the variables inside the buckets would be uninitialized, i.e. null
or default, depending on the type. Since this is not a usual state for a bucket, the dictionary will try to dereference it, causing null pointer exception.
In order to avoid this problem, add synchronization around the call of Add
:
// Add this declaration where you declare TokenCache dictionary
object TokenCacheLock = new object();
...
lock (TokenCacheLock) {
// Add a lock around your access of TokenCache
if (this.TokenCache.ContainsKey(token)) ...
}
Note that since additions to the dictionary happen concurrently with reads, all accesses to TokenCache
need to be synchronized.
A much simpler solution would be using ConcurrentDictionary<K,V>
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With