Access to ASP.net cache causing assembly Modified exception in foreach loop

Ok first first. This is the exception information provided by the support team. I know the line and code where this happens. This happens when calling FirstOrDefault on a dictionary retrieved from the cache.

1) Exception Information
*********************************************
Exception Type: System.InvalidOperationException

Message: Collection was modified; enumeration operation may not execute.

Data: System.Collections.ListDictionaryInternal

Now I wanted to model the problem, and I could do it in a simple ASP.net application.
My page has 2 buttons - Button_Process and Button_Add.
The code is as follows:

 public partial class _Default : System.Web.UI.Page
 {
    protected void Page_Load(object sender, EventArgs e)
    {  
       if (!IsPostBack)
        {
            var data = Cache["key"];

            if (data == null)
            {
                var dict = new Dictionary<int, string>();
                for (int i = 0; i < 10; i++)
                {
                    dict.Add(i, "i");
                }

                Cache["key"] = dict;
            }
        }
    }

    protected void ButtonProcess_Click(object sender, EventArgs e)
    {
        var data = Cache["key"] as Dictionary<int, string>;
        if (data != null)
        {
            foreach (var d in data.Values) //In actual code there is FirstOrDefault here
            {
                Thread.Sleep(1000);

                if (d.Contains("5"))
                {
                    //some operation
                }
            }
        }
    }

    protected void Button2_Click(object sender, EventArgs e)
    {
        var data = Cache["key"] as Dictionary<int, string>;
        if (data != null)
        {
            data.Add(new Random().Next(), "101");
            Cache["key"] = data;
        }
    }
  }

Now suppose there are 2 queries:

1. - button_Process,

2. - button_Add, - blah blah

- , . :
1. for ( FirstOrDefault ). , . - ,
2. - , , .

, . . ?

+4
3

, , . , ( ) . , , - . - ( , - json/xml/binary w/e else), (de) . :

public static class CacheManager
{
    private static readonly Cache MyCache = HttpRuntime.Cache;

    public static void Put<T>(T data, string key)
    {
        MyCache.Insert(key, Serialize(data));
    }

    public static T Get<T>(string key)
    {
        var data = MyCache.Get(key) as string;
        if (data != null)
            return Deserialize<T>(data);
        return default(T);
    }

    private static string Serialize(object data)
    {
        //this is Newtonsoft.Json serializer, but you can use the one you like  
        return JsonConvert.SerializeObject(data);
    }

    private static T Deserialize<T>(string data)
    {
        return JsonConvert.DeserializeObject<T>(data);
    }
}

:

var myObj = new Dictionary<int, int>();
CacheManager.Put(myObj, "myObj");
//...
var anotherObj = CacheManager.Get<Dictionary<int, int>>("myObj");
+3

.NET 3.5. , ConcurrentStack, ConcurentQueue ConcurrentDictionary.

http://www.nuget.org/packages/TaskParallelLibrary

+1

The problem is that the cache object is global for appdomain, and the data stored in them is shared between all requests. The only solution to this problem is to activate the lock when you want to access the collection and then release the lock ( https://msdn.microsoft.com/en-us/library/vstudio/c5kehkcz%28v=vs.100%29.aspx ) (sorry my bad english)

+1
source

All Articles