我实际上正在使用EF Core 6开发一个blazor服务器项目,但我遇到了一个问题。事实上,我想使用自定义服务类在我的应用程序中注册用户,但是,当注册新用户时,UserManager类似乎会冻结。我最初想到的是死锁,所以我使用dotnet dump命令来分析线程数据,但似乎没有线程无限期地保持锁定。
点阻塞在以下行的RegisterService.cs中:
await _userManager.SetUserNameAsync(newUser, registerModel.Username);
我尝试手动设置用户对象数据,如用户名和电子邮件,使用:
newUser.UserName = registerModel.Username;
但是冻结出现在下面的行中:
IdentityResult result = await _userManager.CreateAsync(newUser, registerModel.Password);
请注意,调用UserManager的函数IsEmailUsed运行良好。
我已经没有办法解决我的问题了,所以我终于在这里问了。这是我的代码:
Startup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddMudServices();
services.AddDbContext<Rpg_AgendaContext>(options => options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<User>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<Rpg_AgendaContext>();
services.AddScoped<SignInManager<User>>();
services.AddScoped<UserManager<User>>();
services.AddScoped<RegisterService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<LoginMiddleware<User>>();
app.UseEndpoints(endpoints =>
{
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
注册器剃刀:
@page "/register"
@using System.Text.RegularExpressions
@using Microsoft.AspNetCore.Identity
@using RpgAgenda.Data.Entities
@using Rpg_Agenda.Pages.Shared
@using Rpg_Agenda.Service.RegisterService.Models
@using Rpg_Agenda.Services
@using Rpg_Agenda.Services.RegisterService
@inject NavigationManager navMgr
@inject RegisterService registerService
<MudGrid Justify="Justify.Center">
<MudItem xs="4">
<MudPaper Class="pa-4" Elevation="3">
<MudForm @ref="form">
<ErrorField errorValue="@registerModel.Error"></ErrorField>
<MudTextField T="string" Label="Username" Required="true" RequiredError="Username is required" @ref="username" />
<MudTextField T="string" Label="Email" Required="true" Validation="@(new Func<string, string>(EmailCorrect))" RequiredError="Email is required" @ref="email" />
<MudTextField T="string" Label="Confirm email" Required="true" Validation="@(new Func<string, string>(EmailMatch))" RequiredError="Email confirmation is required" />
<MudTextField T="string" InputType="InputType.Password" Validation="@(new Func<string, string>(PasswordStrength))" Label="Password" Required="true" RequiredError="Password is required" @ref="password"/>
<MudTextField T="string" InputType="InputType.Password" Validation="@(new Func<string, string>(PasswordMatch))" Label="Confirm password" Required="true" RequiredError="Password confirmation is required" />
<div class="d-flex align-center justify-center mt-6">
<MudButton FullWidth="true" OnClick="RegisterClicked" Variant="Variant.Filled" Color="Color.Primary">Register</MudButton>
</div>
</MudForm>
</MudPaper>
</MudItem>
</MudGrid>
@code {
private MudForm form;
private MudTextField<string> username;
private MudTextField<string> email;
private MudTextField<string> password;
private RegisterModel registerModel = new();
private async Task RegisterClicked()
{
await form.Validate();
if(form.IsValid)
{
registerModel.Username = username.Value;
registerModel.Email = email.Value;
registerModel.Password = password.Value;
bool succeed = registerService.RegisterUser(registerModel).Result;
if (succeed)
navMgr.NavigateTo("/");
}
}
private string PasswordStrength(string password)
{
if (password == null)
return null;
if (password.Length < 10)
return "Password must be at least 10 characters";
if (!Regex.IsMatch(password, @"[A-Z]"))
return "Password must contain at least one capital letter";
if (!Regex.IsMatch(password, @"[a-z]"))
return "Password must contain at least one lowercase letter";
if (!Regex.IsMatch(password, @"[0-9]"))
return "Password must contain at least one digit letter";
if (!Regex.IsMatch(password, @"[^a-zA-Z0-9]"))
return "Password must contain at least one special character";
return null;
}
private string PasswordMatch(string passwordConfirmation) => password.Value == passwordConfirmation ? null : "Password doesn't match";
private string EmailMatch(string emailConfirmation) => email.Value == emailConfirmation ? null : "Email doesn't match";
private string EmailCorrect(string email)
{
if (email == null)
return null;
if (Regex.Match(email, @"^([w.-]+)@([w-]+)((.(w){2,3})+)$", RegexOptions.IgnoreCase).Success)
{
if (registerService.IsEmailUsed(email).Result)
return "Email already used !";
return null;
}
else
return "Email format is incorrect";
}
}
RegisterService.cs:
public class RegisterService
{
private readonly UserManager<User> _userManager;
private readonly SignInManager<User> _signInManager;
public RegisterService(UserManager<User> userManager, SignInManager<User> signInManager)
{
_userManager = userManager;
_signInManager = signInManager;
}
public async Task<bool> IsEmailUsed(string email) => await _userManager.FindByEmailAsync(email) != null;
public async Task<bool> RegisterUser(RegisterModel registerModel)
{
User newUser = CreateUser(registerModel).Result;
IdentityResult result = await _userManager.CreateAsync(newUser, registerModel.Password);
if (!result.Succeeded)
{
registerModel.Error = result.Errors.Select(error => error.Description).ToArray().Aggregate((current, next) => $"{current}n{next}");
}
return result.Succeeded;
}
private async Task<User> CreateUser(RegisterModel registerModel)
{
User newUser = new User();
Debug.WriteLine($"ID : {newUser.Id}, UN : {newUser.UserName}, @ : {newUser.Email}");
await _userManager.SetUserNameAsync(newUser, registerModel.Username);
await _userManager.SetEmailAsync(newUser, registerModel.Email);
return newUser;
}
}
谢谢你帮我。
更改
bool succeed = registerService.RegisterUser(registerModel).Result;
至
bool succeed = await registerService.RegisterUser(registerModel);
并且寻找CCD_ 1和CCD_。移除它们,它们可能会死锁。