[英]Infinite await using UserManager with blazor server app
我实际上正在使用 EF Core 6 开发 blazor 服务器项目,但我遇到了问题。 实际上,我想使用自定义服务 class 在我的应用程序中注册用户,但是,在注册新用户时,UserManager class 似乎冻结了。 一开始想到死锁,于是用dotnet-dump命令分析线程数据,但是好像没有线程无限期保持锁。
点阻塞在RegisterService.cs就行了:
await _userManager.SetUserNameAsync(newUser, registerModel.Username);
我尝试使用以下方法手动设置用户 object 数据,例如用户名和 Email:
newUser.UserName = registerModel.Username;
但是冻结出现在以下行中:
IdentityResult result = await _userManager.CreateAsync(newUser, registerModel.Password);
请注意,调用 UserManager 的 function IsEmailUsed 工作正常。
我没有办法尝试解决我的问题,所以我终于在这里问了。 这是我的代码:
启动.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");
});
}
}
寄存器.razor:
@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";
}
}
注册服务.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);
并寻找.Result
和.Wait()
的其他用途。 删除它们,它们可能会死锁。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.