The second operation began in this context before the completion of the previous asynchronous operation

Message:

"System.NotSupportedException was unhandled Message: An unhandled exception of type 'System.NotSupportedException' occurred in mscorlib.dll Additional information: A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe." 

The code:

 public async Task<IEnumerable<UserLangDTO>> ImportLang(int userId) { var userLangs = new List<UserLangDTO>(); using (FirstContext ctx = new FirstContext()) { if (await (ctx.UserLang.AnyAsync(u => u.UserId == userId)) == false) //some exception here userLangs = await ctx.UserLang.AsNoTracking() .Where(ul => ul.UserId == userId) .Join(ctx.Language, u => u.LangID, l => l.LangID, (u, l) => new { u, l }) .Join(ctx.Level, ul => ul.u.LevelID, le => le.LevelID, (ul, le) => new { ul, le }) .Select(r => new UserLangDTO { UserId = r.ul.u.UserId, Language = r.ul.l.Language, Level = r.le.Level, }).ToListAsync().ConfigureAwait(false); } using (SecondContext ctx = new SecondContext()) { if ( await (ctx.UserLangs.AnyAsync(u => u.UserId == userId)) == true && userLangs.Any()) ctx.UserLangs.RemoveRange(ctx.UserLangs.Where(u => u.UserId == userId)); if (await hasUserLangs && userLangs.Any()) { userLangs.ForEach(async l => { var userLanguage = new UserLang(); userLanguage.UserId = userId; userLanguage.LanguageId = await ctx.Languages.AsNoTracking() .Where(la => la.NameEn == l.Language) .Select(la => la.Id).FirstOrDefaultAsync().ConfigureAwait(false); userLanguage.LevelId = await ctx.Levels.AsNoTracking() .Where(la => la.NameEn == l.Language) .Select(la => la.Id).FirstOrDefaultAsync().ConfigureAwait(false); ctx.UserLangs.Add(userLanguage); }); } await ctx.SaveChangesAsync().ConfigureAwait(false); } return userLangs; } 

What I tried:

I'm not sure what I'm doing wrong, I tried different things like:

one.

 await Task.Run(() => Parallel.ForEach(strings, s => {    DoSomething(s); })); 

2.

 var tasks = userLangs.Select(async l => { //rest of the code here } await Task.WhenAll(tasks); 

3.

 var tasks = userLangs.Select(async l => { //rest of the code here } await Task.WhenAll(tasks); await ctx.SaveChangesAsync().ConfigureAwait(false); 
  1. Other trial and error attempts that I do not repeat now

What am I doing wrong?

+6
source share
1 answer

Here is your problem:

 userLangs.ForEach(async 

This creates the async void method because ForEach does not understand asynchronous delegates. Thus, the ForEach body will execute simultaneously, and the Entity Framework does not support simultaneous asynchronous access.

Change ForEach to ForEach and you should be good:

 foreach (var l in userLangs) { var userLanguage = new UserLang(); userLanguage.UserId = userId; userLanguage.LanguageId = await ... } 

For more information, see the “avoid async void” guide in my article

+18
source

Source: https://habr.com/ru/post/1011915/


All Articles