4

If I made more than one API call at the same time getting error

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 in this context. Any instance members are not guaranteed to be thread-safe.

Exception is thrown from var identity = await base.currentUserService.CreateIdentity(user); as both requests are made at the same time and CreateIdentity method of the previous request is still not finished!

How to solve the above scenario?

I want to wait for IsValidRequest calling in CustomKeyAuthenticationAttribute before the previous request finish.

Here is sample code

public class CustomKeyAuthenticationAttribute : AuthorizeAttribute
{
    [Dependency]
    public IAuthService AuthService { get; set; }

    public override async Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
    {
         var isValid = await AuthService.IsValidRequest(key-from-request-header);
         if(!isValid){
             return;             
         }
         await base.OnAuthorizationAsync(actionContext, cancellationToken);
    }
}

   // In side AuthService
    public async Task<bool> IsValidRequest(string key)
    {
        if (key-in-db)
        {
            var user = await base.currentUserService.GetUserById(userId-from-request-headers);

            var identity =  await base.currentUserService.CreateIdentity(user);

            var principal = new GenericPrincipal(identity.Result, new string[0]);
            
            HttpContext.Current.User = principal;

            return true;
        }
    return false
 }

  // Inside currentUserService.CreateIdentity method

    public async Task<ClaimsIdentity> CreateIdentity(CustomUser user) {
       return await userManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
    }

Edit

stackTrace: " at System.Data.Entity.Internal.ThrowingMonitor.EnsureNotEntered() at System.Data.Entity.Internal.Linq.InternalSet1.FindAsync(CancellationToken cancellationToken, Object[] keyValues) at System.Data.Entity.DbSet1.FindAsync(CancellationToken cancellationToken, Object[] keyValues) at System.Data.Entity.DbSet1.FindAsync(Object[] keyValues) at Microsoft.AspNet.Identity.EntityFramework.EntityStore1.GetByIdAsync(Object id) at Microsoft.AspNet.Identity.EntityFramework.UserStore6.<GetUserAggregateAsync>d__6c.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNet.Identity.TaskExtensions.CultureAwaiter1.GetResult() at Microsoft.AspNet.Identity.UserManager2.<GetRolesAsync>d__ac.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNet.Identity.TaskExtensions.CultureAwaiter1.GetResult() at Microsoft.AspNet.Identity.ClaimsIdentityFactory2.<CreateAsync>d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()

Yogen Darji
  • 3,230
  • 16
  • 31

1 Answers1

1

I would need to see the code behind

var identity =  await base.currentUserService.CreateIdentity(user);

But my guess is that you are setting the DbContext as a shared instance between the various requests. You need to use a different context per thread.

Check this question here for more information as I think it's the same problem.

Another similar problem on entity framwork documentation

Athanasios Kataras
  • 25,191
  • 4
  • 32
  • 61