ASP.NET Web API - secure thread logic for updating an object

I have the following way of adding or updating an object of type Item for some user. This method is part of the Service class, a new instance of which is created for each request.

 public async Task SaveItem(int userId, string name) { var item = await _context.Items.Where(i => i.UserId == userId).SingleOrDefaultAsync(); if (item == null) { item = new Item { UserId = userId, Name = name }; _context.Items.Add(item); } else { item.Name = name; _context.Entry(item).State = System.Data.Entity.EntityState.Modified; } await _context.SaveChangesAsync(); } 

The problem is that two simultaneous requests can create two elements for the same user, which is invalid. For me, this looks like a fairly common piece of code, and I wonder what is the standard way to solve this concurrency problem.

+5
source share
4 answers

You must correctly handle Concurrency Conflicts in your application.

1.Pessimistic Concurrency (lock)

If your application really needs to prevent accidental data loss in Concurrency, one way to do this is to use database locks. This is called pessimistic concurrency. For example, before you read rows from a database, you request a lock to read or to update access. If you block a row to access the update, no other users will be allowed to block the row, either for read-only access or for access to the update, because they will receive a copy of the data that is being modified. If you block the line for read-only access, others may also block it for read-only access, but not for updating.

2.Optimistic Concurrency

An alternative to pessimistic concurrency is optimistic concurrency. Optimistic Concurrency means resolving Concurrency conflicts, and then react accordingly if they do.

Read Concurrency Handling with the Entity Framework article for more information.

+2
source

If the combination of UserId and Name for an object must be unique, make it unique in the database.

You can try to solve the problem with static lock objects ... but that will only make it slow and hard to understand / supportive.

+1
source

You can have two separate functions: one that creates, and one that updates. Or you can try updating, and if that fails, create one and remember to specify a unique index in your database.

0
source

If the UserId field UserId marked as unique (or an identity that is also unique), you're already fine. Whenever you fall into this short period of time to add more than one item with the same UserId at the same time, only the first will succeed and all the rest will not be added.

0
source

All Articles