繁体   English   中英

Can't update IdentityUser - double SQL update

[英]Can't update IdentityUser - double SQL update

I've got an angular website with Mvc's REST Api. I have just updated it from .net core 2.0 to the newest .Net 6, along with EF Core and AspNetCore.Identity.

I have an extended the AspNetCore's IdentityUser. When I try to update it, there are 2 update requests sent (I found that out using the Sql Server Profiler) - one containing the updated column and the another one resetting it back to the original value. It happens only to the IdentityUser, other entities work normally. As a result, I can't update any user.

They can occasionally come in different order so sometimes the update does work (but more often doesn't).

e.g. when I try something like this

        var user = await UserAccountManager.UserManager.FindByIdAsync(id);
        user.Name = model.Name;
        var result = await UserAccountManager.UserManager.UpdateAsync(user);

After this I would see something like this in the profiler: profiler - 2 updates

As you can see, there are 2 subsequent updates which differ by the Name field and the ConcurrencyStamp.

I've tried to just fetch the user directly from the context e.g.:

                var xx = await Context.Users.SingleOrDefaultAsync(m => m.Id == id);
                xx.Name = model.Name;
                var aa = await Context.SaveChangesAsync();

Same thing.

Even wrapping it all in a transaction didn't work - the SQL requests are separated out but after updating the user there is still another SQL query sent that reverts it back.

I'm pasting in the ConfigureServices function (from Startup.cs) if that helps:

public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().AddNewtonsoftJson(options => {
                                             options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
                                             options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                                         });

        services.AddDbContext<OffWorkDbContext>(options =>
                                                    {
                                                        options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"], b => b.MigrationsAssembly("Hicron.OffWorkPlanner.DataAccessComponent"));
                                                    });

        // add identity
        services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddEntityFrameworkStores<OffWorkDbContext>()
            .AddDefaultTokenProviders();

        services.Configure<IdentityOptions>(o => 
                                            {
                                                // User settings
                                                o.User.RequireUniqueEmail = true;
                                                o.Password.RequireDigit = false;
                                                o.Password.RequireNonAlphanumeric = false;
                                                o.Password.RequireUppercase = false;
                                                o.Password.RequireLowercase = false;
                                                //o.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name;
                                                //o.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject;
                                                //o.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;
                                            });

        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
                          {
                              options.TokenValidationParameters = new TokenValidationParameters
                                                                  {
                                                                      ValidateIssuer = true,
                                                                      ValidateAudience = true,
                                                                      ValidateLifetime = true,
                                                                      ValidateIssuerSigningKey = true,
                                                                      ValidIssuer = Configuration["Token:Issuer"],
                                                                      ValidAudience = Configuration["Token:Issuer"],
                                                                      IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration["Token:Key"]))
                                                                  };
                          });

        services.AddAuthorization(options =>
                                  {
                                      //add authorization policies 
                                      options.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
                                          .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
                                          .RequireAuthenticatedUser().Build());
                                  });

        Mapper.Initialize(cfg =>
                          {
                              cfg.AddProfile<AutoMapperProfile>();
                          });


        // Add cors
        services.AddCors();

        // Add framework services.
        services.AddMvc(options =>
        {
            options.EnableEndpointRouting = false;
        });


        // In production, the Angular files will be served from this directory
        services.AddSpaStaticFiles(configuration =>
                                   {
                                       configuration.RootPath = "ClientApp/dist";
                                   });

        services.Configure<EmailConfig>(Configuration.GetSection("SmtpConfig"));
        services.AddScoped<IEmailNotifications, EmailNotifications>();
        services.AddScoped<IUserAccountManager, UserAccountManager>();
        services.AddScoped<ITeamService, TeamService>();
        services.AddScoped<IUserService, UserService>();
        services.AddScoped<IDayService, DayService>();
        services.AddScoped<IProjectService, ProjectService>();
        services.AddScoped<IUserCalendarItemService, UserCalendarItemService>();
        services.AddScoped<IDepartmentService, DepartmentService>();
        services.AddTransient<IDatabaseInitializer, DatabaseInitializer>();
    }

Please help me figure out what's going on here (and update the user).

好的,事实证明有 2 个并发请求 - 第 2 个是更新角色,即使角色没有明确更新用户,它确实在后台更改了并发时间戳,并且出于某种原因它正在这样做过时的价值观。

为了解决这个问题,我们只是将这两个请求放在一起。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM