HerrimanCoder
HerrimanCoder

Reputation: 7218

Collection was modified in async application?

I have the following code in my .NET 4.6.2 winforms app:

paramList is an OrderedDictionary.

if ( paramList != null ) {
     foreach ( DictionaryEntry param in paramList ) {
         command.Parameters.AddWithValue(param.Key.ToString(), param.Value);
     }
}

It always worked great until I started implementing more async/multithreaded processing in the application. Now, sporadically, I get the following error when the above code runs:

System.InvalidOperationException: 'Collection was modified; enumeration operation may not execute.'

It doesn't seem like I'm modifying the collection at all, so I don't know why it's complaining.

I understand the discussion/solutions in these posts, but it doesn't seem to apply to mine:

Collection was modified exception

System.InvalidOperationException: Collection was modified

What is the best way to make this thread safe?

EDIT #1

I have this now:

private static object syncLock = new object();

[...]

lock ( syncLock ) {
   if ( paramList != null ) {
      foreach ( DictionaryEntry param in paramList ) {
          command.Parameters.AddWithValue(param.Key.ToString(), param.Value);
      }
   }
}

I ran it a few times and then the problem came back again:

enter image description here

How can this still be happening, even inside a lock()? What can I do?

EDIT #2

paramList is always created by the caller and passed into a function, for example:

var paramList = new OrderedDictionary();
paramList.Add("RuleID", btRule.RuleID);
paramList.Add("TypeSeq", 0);
paramList.Add("Type", btRule.Action);

bool result = await ExecuteQueryAsync(sql, paramList, connection);

public static async Task<bool> ExecuteQueryAsync(string sql, OrderedDictionary paramList, SqlConnection connection) {
     try {
        using ( SqlCommand command = new SqlCommand(sql, connection) ) {
           command.CommandType = CommandType.Text;

           lock ( syncLock ) {
              if ( paramList != null ) {
                 foreach ( DictionaryEntry param in paramList ) {
                    command.Parameters.AddWithValue(param.Key.ToString(), param.Value);
                 }
              }
           }

           command.CommandTimeout = 0;
           await command.ExecuteNonQueryAsync();
        }
        return true;
     }
     catch ( Exception ex ) {
        [...]
     }
}

Upvotes: 0

Views: 743

Answers (1)

tmaj
tmaj

Reputation: 35037

Because of if ( paramList != null ) { my guess is that paramList is reused by different actors. You will need to use a different instances per unit of work.

Upvotes: 1

Related Questions