【问题标题】:C# Thread Safe CreateIdentityAsync on AuthorizeAttributeAuthorizeAttribute 上的 C# 线程安全 CreateIdentityAsync
【发布时间】:2020-04-10 22:19:42
【问题描述】:

如果我同时调用more than one API 会出错

在前一个异步操作完成之前,在此上下文上启动了第二个操作。在此上下文中调用另一个方法之前,使用“等待”确保任何异步操作都已完成。不保证任何实例成员都是线程安全的。

var identity = await base.currentUserService.CreateIdentity(user); 抛出异常,因为两个请求同时发出,而前一个请求的 CreateIdentity 方法仍未完成!

上述情况如何解决?

我想在上一个请求完成之前等待IsValidRequest 调用CustomKeyAuthenticationAttribute

这里是示例代码

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);
    }

编辑

stackTrace:" 在 System.Data.Entity.Internal.ThrowingMonitor.EnsureNotEntered() 在 System.Data.Entity.Internal.Linq.InternalSet1.FindAsync(CancellationToken cancellationToken, Object[] keyValues) at System.Data.Entity.DbSet1.FindAsync(CancellationToken cancelToken, Object[] keyValues) 在 System.Data.Entity.DbSet1.FindAsync(Object[] keyValues) at Microsoft.AspNet.Identity.EntityFramework.EntityStore1.GetByIdAsync(对象 身份证)在 Microsoft.AspNet.Identity.EntityFramework.UserStore6.&lt;GetUserAggregateAsync&gt;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() 在 Microsoft.AspNet.Identity.UserManager2.&lt;GetRolesAsync&gt;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() 在 Microsoft.AspNet.Identity.ClaimsIdentityFactory2.&lt;CreateAsync&gt;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()

【问题讨论】:

    标签: c# asp.net-web-api thread-safety asp.net-identity


    【解决方案1】:

    我需要看看后面的代码

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

    但我的猜测是您将 DbContext 设置为各种请求之间的共享实例。您需要为每个线程使用不同的上下文。

    检查this question here for more information,因为我认为这是同样的问题。

    另一个类似的问题on entity framwork documentation

    【讨论】:

    • 使用CreateIdentity 方法更新问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-08
    • 1970-01-01
    • 2015-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多