Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are private member variables really thread safe in asp.net code behind class?

I am seeing a random exception "Collection was modified; enumeration may not execute" - InvalidOperationException.

The exception points to foreach line in the code snippet below, I know this happens when a collection is modified while enumerating.

However in my scenario, I don't see a real chance of it happening - UNLESS private member is not thread safe.. I may be wrong, but this where I need help to understand and figure out.

Here is how my code looks

I have code behind class which has a private collection like

private Dictionary<string, string> _someDictionary = SomeConstantClass.ConstantValue;

In the page prerender complete event, I am enumerating the dictionary

protected override void OnPagePreRenderComplete(object sender, EventArgs e){
     _someDictionary["AnotherKey"] = "Another value";

     foreach(var dataValuePair in _SomeDictionary){
         //Do some operation
     }
}

I also have a public property which can modify this collection, but it set in the ascx file like

<tc: UserControlA runat="server" id="abc" CustomProperty="true" />

and here is its implementation,

public bool CustomProperty{
    set{
         if (value)
            _someDictionary["CustomProperty"] = "Custom Value";
    }
}

It certainly modified my member variable collection - But as per my understanding this property should be fired and done in the Control Init itself.

So, I still dont see a scenario where the collection is modified during the pre render complete event.

Any idea what could cause the exception to occur??

other notes: the page certainly has many update panels though this specific usercontrol does not do anything fancy and does not even have postback scenario. From the log I see that the issue is happening in HTTP GET request to the page.

Moreover: Suggest me a way (if any) to reproduce this.

For my friends who were interested to know the SomeConstantClass.ConstantValue, here it is

class SomeConstantClass{
  public static Dictionary<string, string> ConstantValue = new Dictionary<string, string> {
                      {"ABCD", "EFGH"},
                      {"HIJK", "LMNO"}
                   };
  }
like image 762
humblelistener Avatar asked Jan 19 '23 08:01

humblelistener


1 Answers

If you are returning the same instance from SomeConstantClass.ConstantValue then multiple pages will have the private member variable pointing to the same object. This will lead to the object being changed on the init of one page while its being iterated on the OnPagePreRenderComplete of another page.

Make sure that you return a new instance of the dictionary in each access to SomeConstantClass.ConstantValue. Example:

public static Dictionary<string, string> ConstantValue
{
    get
    {
        return new Dictionary<string, string>
        {
            {"ABCD", "EFGH"},
            {"HIJK", "LMNO"}
        };
    }
}

This way each page will have it own dictionary object to work with. This is the quick solution, you could refactor the logic so that you don't need to have to create a new dictionary for each page.

Basically private member variables are only thread safe if they reference an object that is private to that page and no one else knows about that object or the object itself is designed to be thread-safe. Encapsulating access to a non thread-safe static object through a private member will not make it thread safe.

like image 157
João Angelo Avatar answered Jan 23 '23 09:01

João Angelo