新 ASP.NET MVC 6标识中 AspNetUsers 表中的 ConcurrencyStamp 列的用途是什么?

在新的 ASP.NET MVC 6标识中,AspNetUsers表中的 ConcurrencyStamp列的用途是什么?

这是 AspNetUsers表的数据库模式:

enter image description here

AspNetRoles表中也有:

enter image description here

我记得 ASP.NET MVC 5标识中没有这个标识。

到目前为止,我注意到它似乎有 GUID 值,因为它是用以下代码定义的:

/// <summary>
/// A random value that must change whenever a user is persisted to the store
/// </summary>
public virtual string ConcurrencyStamp { get; set; } = Guid.NewGuid().ToString();

但是这个文档对于我来说不足以理解它在哪些情况下被使用。

43295 次浏览

From the source code itself

    /// <summary>
/// A random value that should change whenever a role is persisted to the store
/// </summary>
public virtual string ConcurrencyStamp { get; set; } = Guid.NewGuid().ToString();

Basically, see it as it is named. A stamp that is used to identify the current version of the data. If you change it, so does the stamp.

So if two concurrent updates comes in at the same time, they must have the same stamp or one of them should be discarded.

Hence the name, ConcurrencyStamp.

To follow up on Maxime's reply:

If you look at the implementation of IdentityDbContext in the OnModelCreating() method, you'll find:

builder.Entity<TUser>(b =>
{
....
b.Property(u => u.ConcurrencyStamp).IsConcurrencyToken();
....

and in the UserStore.UpdateAsync(...)-method:

    Context.Update(user);
try
{
await SaveChanges(cancellationToken);
}
catch (DbUpdateConcurrencyException)
{
return IdentityResult.Failed(ErrorDescriber.ConcurrencyFailure());
}

So, it indeed does what it's supposed to do: prevent concurrent updates on a user object. The token is merely used "under the hood" in the ASP Identity EntityFramework module. Basically, if a concurrent update of one user object occurs, the DB context throws DbUpdateConcurrencyException.

As the name state, it's used to prevent concurrency update conflict.

For example, there's a UserA named Peter in the database 2 admins open the editor page of UserA, want to update this user.

  1. Admin_1 opened the page, and saw user called Peter.
  2. Admin_2 opened the page, and saw user called Peter (obviously).
  3. Admin_1 updated user name to Tom, and save data. Now UserA in the db named Tom.
  4. Admin_2 updated user name to Thomas, and try to save it.

What would happen if there's no ConcurrencyStamp is Admin_1's update will be overwritten by Admin_2's update. But since we have ConcurrencyStamp, when Admin_1/Admin_2 loads the page, the stamp is loaded. When updating data this stamp will be changed too. So now step 5 would be system throw exception telling Admin_2 that this user has already been updated, since he ConcurrencyStamp is different from the one he loaded.

Also important to realize that this is actually a data layer feature. The schema for Identity defines the column as being a concurrency column but doesn't actually use it.

There's no logic going on inside the Identity codebase - it's only when EFCore actually goes to save it that it kicks in.

https://learn.microsoft.com/en-us/ef/core/modeling/concurrency

EF Code First - IsConcurrencyToken()