【问题标题】:Lock EF 6 insert when calling same url multiple times at the same time同时多次调用相同的url时锁定EF 6插入
【发布时间】:2016-11-18 07:23:00
【问题描述】:

我有一个 ASP.NET MVC 6 应用程序。当用户在 Angular 中进入客户端时,我会调用 ASP.NET 的 Async API。在某些地方,我会调用 Api 3-4 次以获取其他资源。

我还在我的数据库中保留了一个用户表,与 EF 6 连接。在这里,当输入的用户(使用 Windows Auth)不存在时,我创建一个新的用户行并添加“公共”角色给他。

但是,当用户进入首先调用Api 3-4次的页面时,用户被创建了3-4次,因为'Create'没有锁定表,因此创建了3次用户。

如何锁定表(在我的情况下为存储库)以让下一次调用等待锁定被移除,然后执行“GetAsync”以检查用户是否存在?

被调用 3 次的代码:

        var currentUserName = User.Identity.Name;
        var currentUser = await _userRepository.GetAsync(u => u.UserName == currentUserName);

        // Create user that does not yet exist
        if (currentUser != null) return HttpBadRequest();

        var user = new User(currentUserName);

        using(new CreatedBySystemProvider(_userRepository))
        {
            _userRepository.Add(user);
            await _userRepository.SaveChangesAsync();
            await user.AddRoleAsync(AppSumRoles.Authenticated);
            /* Temporary add SysAdmin role */
            if(string.Equals(currentUserName, @"BIJTJES\NilsG", StringComparison.CurrentCultureIgnoreCase))
            {
                using(new CreatedBySystemProvider(_userRoleRepository))
                {
                    await user.AddRoleAsync(AppSumRoles.SysAdmin);
                }
            }
            currentUser = await _userRepository.GetAsync(u => u.Id == user.Id);
        }

        return Ok(currentUser);

【问题讨论】:

  • 在请求中使用某些内容作为用户的唯一标识符。像他们的 IP 之类的东西
  • 如果用户名应该是唯一的,您可以在用户名上创建唯一索引并处理异常,以防多个并行请求尝试创建同一个用户。

标签: c# asp.net angularjs asp.net-mvc entity-framework


【解决方案1】:

考虑将 CreateUser 代码移动到单独的 API 中。用户创建应该是一个单独的用例,而不是所有其他用例的隐含部分。不要混淆顾虑。

【讨论】:

    【解决方案2】:

    您应该考虑重构您的用户创建过程。但只是为了你的问题,你可以做这样的事情

    (详情请见http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx)

    private static readonly AsyncLock asyncLocker = new AsyncLock(); 
    
    var currentUserName = User.Identity.Name;
    
    using(var releaser = await asyncLocker.LockAsync()) 
    {
        var currentUser = await _userRepository.GetAsync(u => u.UserName == currentUserName);
    
        // Create user that does not yet exist
        if (currentUser != null) return HttpBadRequest();
    
        var user = new User(currentUserName);
    
        using(new CreatedBySystemProvider(_userRepository))
        {
            _userRepository.Add(user);
            await _userRepository.SaveChangesAsync();
            await user.AddRoleAsync(AppSumRoles.Authenticated);
            /* Temporary add SysAdmin role */
            if(string.Equals(currentUserName, @"BIJTJES\NilsG", StringComparison.CurrentCultureIgnoreCase))
            {
                using(new CreatedBySystemProvider(_userRoleRepository))
                {
                    await user.AddRoleAsync(AppSumRoles.SysAdmin);
                }
            }
            currentUser = await _userRepository.GetAsync(u => u.Id == user.Id);
        }
    }
    
    return Ok(currentUser);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-27
      • 1970-01-01
      相关资源
      最近更新 更多