方法在 Page_Load 中被乱序调用了两次

Method called twice out of order in Page_Load

我在 SharePoint Stack Exchange 中询问过这个问题,但认为它可能不是特定于 SharePoint 的问题,可能与 .NET 页面生命周期有更多关系。原题可见here.

我正在为 SharePoint 2013 编写 Web 应用程序,并且正在 运行 关注一些有趣的行为。基本上,我正在发出一系列网络请求,但首先需要将这些请求存储在 Dictionary 中以备后用。但是,如果我在调试时打开 3 个选项卡并同时点击它们,我会看到 Dictionary 对象未清空并在它尝试多次添加相同端点时导致异常。下面是应用的相关代码:

public partial class TestControl : UserControl
{
    protected static Dictionary<string, string> _endpoints = new Dictionary<string, string>();

    protected void Page_Load(object sender, EventArgs e)
    {
        //clear the lists of endpoints each time the page is loaded
        _endpoints.Clear();
        ...
        MethodThatAddsToDictionary();
       ...
    }

    public static void MethodThatAddsToDictionary()
    {
        ...
        _endpoints.Add(response.First(), response.Last());
    }
}

调试,有时 MethodThatAddsToDictionary()_endpoints.Clear() 之前被调用两次 运行 在 Page_Load 事件的顶部,我会得到一个 ArgumentException 说:

an item with the same key has already been added

我觉得我缺少关于应用程序生命周期的一些基本知识,但到目前为止还没有找到任何有用的东西。我可以将 .Add() 包装在有条件的条件中以在添加之前检查密钥,但我觉得那是创可贴。我错过了什么?

提前致谢!

嗯哼…… 如果您不使用静态字典作为一种共享内存缓存,您可以删除示例代码中的所有静态关键字。在那种情况下,您也不需要调用 Clear() 方法。

如果您将 static 词典用作一种内存缓存(我不推荐这样做),您可能会遇到对页面的多次调用会导致竞争条件,因为它们可能会被处理通过不同的线程。为了解决这个问题,作为创可贴,您可以使用锁定语句在对字典的非线程安全调用上强制线程同步,如下所示:

public partial class TestControl : UserControl
{
    protected static Dictionary<string, string> _endpoints = 
                                      new Dictionary<string, string>();

    //lock object needs to be static in this case
    private static object _lockObject = new object();

    protected void Page_Load(object sender, EventArgs e)
    {
        lock(_lockObject) //only one thread may pass at the same time,
                          //others will wait.
        {
            //clear the lists of endpoints each time the page is loaded
            _endpoints.Clear();
            ...
            MethodThatAddsToDictionary();

         }
     }

     public static void MethodThatAddsToDictionary()
     {
         ...
         _endpoints.Add(response.First(), response.Last());
     }
 }

请注意;这是一个肮脏的修复,将有效地取消针对此特定调用的网络服务器的所有多线程优化(因此会导致性能下降)。