Method called twice out of order in Page_Load

2019-07-25 16:57发布

问题:

I asked this over in the SharePoint Stack Exchange but figured it might not be a SharePoint-specific question and might have more to do with the .NET page lifecycle. The original question can be found here.

I am writing a web app for SharePoint 2013 and am running into some interesting behavior. Basically, I am making a series of web requests, but first need to store those in a Dictionary for use later. However, if I open 3 tabs while debugging and hit them at the same time, I see the Dictionary object is not emptied and causes an exception when it tries to add the same endpoint multiple times. Here is the relevant code of the app:

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

Debugging, sometimes MethodThatAddsToDictionary() is called twice before the _endpoints.Clear() is run at the top under the Page_Load event and I'll get an ArgumentException saying:

an item with the same key has already been added

I feel like I'm missing something basic about the lifecycle of the app but haven't found anything that works so far. I could wrap the .Add() in a conditional to check for the key before I add it, but I feel like that is a bandaid. What am I missing?

Thanks in advance!

回答1:

ehhmm... If you are not using the static dictionary as a sort of shared memory cache, you can drop all the static keywords your example code. In that case you also don't need to call the Clear() method.

If you use your static dictionary as a sort of memory cache, which I wouldn't recommend, you might experience that multiple calls to your page will result in a race condition, since they might be handled by different threads. In order to fix this, you can, as a band-aid, use a lock statement to force thread synchronization on the non-thread-safe call to the dictionary like this:

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

Please note; this is a dirty fix and will effectively cancels all multithreading optimizations of the webs-server for this specific call (and thus causes a performance penalty).