In the following example we may run into a concurrency error where if the sender decides to send funds to 2 different receivers in the same time then both receivers may get the money while the sender will only be charged once.
public async Task SendMoney(int amount, int sender, int receiver)
{
await using var dbContext = new ApplicationDbContext();
var person1 = await dbContext.Persons.FirstOrDefaultAsync(p => p.Id == sender);
var person2 = await dbContext.Persons.FirstOrDefaultAsync(p => p.Id == receiver);
if (person1.Balance >= amount)
{
person1.Balance -= amount;
person2.Balance += amount;
}
await dbContext.SaveChangesAsync();
}
What would be the best way to avoid such scenario and make this operation secure?
Is introducing optimistic locking by adding timestamp property [Timestamp] public byte[] Version { get; set; } to the Person model enough to make sure there is no way of duplicating funds?
I mostly care about the security of avoiding duplication. Properly handling exceptions such as DbUpdateConcurrencyException in order to provide smooth user experience is not part of my question.