在lock语句中使用async

Mil*_*adi 2 c# multithreading thread-synchronization async-await asp.net-core

我使用 ASP.NET Core Identity,通过 Jmeter 应用程序,我向我的 Web 应用程序发送多个请求以创建用户,它使用同一电子邮件创建了多个用户,尽管我的RequireUniqueEmailtrue

services.AddIdentity<User, Role>(identityOptions =>
{
    identityOptions.User.RequireUniqueEmail = true;
});
Run Code Online (Sandbox Code Playgroud)

当我一一发送请求时,一切正常,并在这段代码中给我重复的电子邮件错误

var result = await _userManager.CreateAsync(userToCreate, userPassword);
Run Code Online (Sandbox Code Playgroud)

但是当我使用 Jmeter 发送多个请求时,上面的代码无法处理重复的电子邮件,并且在 Jmeter 请求完成后,我打开 SQL Server,我看到至少创建了 10 条具有相同电子邮件的记录。我搜索了这个问题并得到了这个解决方案Using lock

private static readonly object lockObj = new object();
lock(lockObj)
{
    var result = await _userManager.CreateAsync(userToCreate, userPassword);
}
Run Code Online (Sandbox Code Playgroud)

但它给了我错误并说“你不能在锁定语句中使用await”,第二个问题是ASP.NET Core Identity没有用于创建的Sync方法。如何在 ASP.NET Core Identity 中创建 create 的同步方法?

Mag*_*nus 7

您应该在数据库中强制执行此操作,而不是在代码中使用锁或信号量。例如,想象一下您的应用程序是否需要扩展到多个服务器。

UNIQUE constraint在数据库中的电子邮件列上添加一个。插入新用户时,如果电子邮件已存在,则会出现错误,您可以在应用程序中处理该错误。


Fre*_*man 5

首先,你不能使用lock带有await关键字的语句!在你的情况下,也许最好使用对象,因为一次SemaphoreSlim只有一个请求可以进入关键部分(在WaitAsync和之间)!Release

private static readonly SemaphoreSlim semaphore = new SemaphoreSlim(1);

// rest of your code

async Task CreateUserAsync(User userToCreate, string userPassword)
{
    await semaphore.WaitAsync();
    try
    {
        var result = await _userManager.CreateAsync(userToCreate, userPassword);
    }
    finally
    {
        semaphore.Release();
    }
}
Run Code Online (Sandbox Code Playgroud)

如果需要同步版本,还可以创建一个包装方法,封装异步调用并阻塞执行,直到操作完成。