【问题标题】:NullReferenceException when adding to Dictionary in Asynchronous context在异步上下文中添加到字典时出现 NullReferenceException
【发布时间】:2015-05-07 22:51:33
【问题描述】:

我有一个非常奇怪的行为,如下图所示:

正如您在 Watch 窗口中看到的,所有可能是 null 的东西都不是 null

这里是函数的完整代码:

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

我使用了 Find All References 功能,这是我唯一使用构造函数和声明的地方(我将它用于整个 Web 应用程序):

public class IdentityController : Controller
{

    private static EmailAdpater EmailAdapter = new EmailAdpater();
    private static UserIdentityTokenShortener TokenShortener = new UserIdentityTokenShortener();
    public static LoginTokenManager LoginTokenManager = new LoginTokenManager();
    ...

有人遇到过这个问题吗?我做错了什么?

编辑:添加了 StackTrace 和详细信息 EDIT2:编辑标题,以便将来的人可以搜索此主题,以防遇到同样的问题。

   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()

【问题讨论】:

  • 点击“查看详情”,发布完整的堆栈跟踪。
  • 还有……你使用多线程吗?
  • 我们无法用这段代码重现它。
  • 我也在考虑“检查堆栈跟踪”,但这听起来像是 Intellitrace 的工作。
  • @DatVM:10 次中有 9 次会遇到并发问题。选择答案并使用ConcurrentDictionary 并注意该课程中的任何其他成员。它也可能存在并发问题。

标签: c# .net dictionary asp.net-mvc-5 nullreferenceexception


【解决方案1】:

我使用多线程

这几乎肯定是问题所在:因为您的代码中的所有内容都是null-checked 和/或使用非null 的值创建的,所以唯一可能发生问题的地方是@987654324 的实现@。

当达到字典的容量时,集合会重新分配其内部数据结构。如果一个线程在另一个线程执行重新分配的过程中捕获字典,则存储桶内的一些变量将未初始化,即null 或默认值,具体取决于类型。由于这不是存储桶的常见状态,因此字典会尝试取消引用它,从而导致空指针异常。

为了避免这个问题,围绕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)) ...
}

请注意,由于对字典的添加与读取同时发生,因此对 TokenCache 的所有访问都需要同步。

一个更简单的解决方案是使用ConcurrentDictionary&lt;K,V&gt;

【讨论】:

  • 非常感谢,很高兴知道。我还将编辑标题,以便将来遇到问题的人可以搜索此主题。
【解决方案2】:
    public static LoginTokenManager LoginTokenManager = new LoginTokenManager();

(我将它用于整个 Web 应用程序):

你的问题。 Dictionary&lt;TKey, TValue&gt; 类型不是线程安全的。见Thread safety with Dictionary<int,int> in .Net

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-21
    • 2011-12-30
    • 2011-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-04
    相关资源
    最近更新 更多