同时多次调用相同的URL时锁定EF 6插入

时间:2016-07-15 07:17:37

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

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

我还在我的数据库中保留了一个User表,与EF 6连接。当我输入的用户(使用Windows Auth)尚未存在并添加'Public'角色时,我创建了一个新的User行对他来说。

但是,当用户首次进入调用Api 3-4次的页面时,用户会被创建3-4次,因为“创建”没有锁定表格,从而创建了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);

2 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

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

(有关详情,请参阅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);