AspNetCore.Identity userManager.FindByNameAsync 在找到所述用户时抛出访问冲突异常

AspNetCore.Identity userManager.FindByNameAsync throws Access Violation Exception upon finding said user

我正在使用 Identity 和 JWT 令牌制作一个简单的用户注册端点。使用 userManager.FindByNameAsync(username) 时,如果没有找到任何用户,它会按预期工作 returning null 并继续注册过程。如果已经存在具有相同用户名的用户,它会抛出访问冲突异常并且服务器停止。 这是我为了测试目的硬编码方法参数的验证:

User userExists = await _userManager.FindByNameAsync("Andrew");
            
            
            if (userExists != null)
                throw new Exception("User already exists");

来自数据访问层的自定义 IdentityUser:

public class User : IdentityUser
{
    public string Name { get; set; }
    public DateTime BirthDate { get; set; }
    public DateTime JoinedAt {
        get { return DateTime.Now; }
        set { JoinedAt = value; }
    }

    public ICollection<ExampleEntity>? ExampleEntities { get; set; }

    public ExampleEntity? ExampleEntity { get; set; }
    public ICollection<ExampleEntity>? ExampleEntities2 { get; set; }
}

以及身份和 ExampleEntity 的 AppDbContext

public class AppDbContext : IdentityDbContext<User>
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) {}

    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.Entity<User>()
            .HasMany(j => j.ExampleEntities)
            .WithOne(j => j.User);

        builder.Entity<Property>()
           .HasMany(p => p.Users)
           .WithOne(t => t.ExampleEntity)
           .HasPrincipalKey(t => t.Id)
           .OnDelete(DeleteBehavior.NoAction);

        builder.Entity<ExampleEntity>()
            .HasOne(p => p.User)
            .WithMany(p => p.ExampleEntities2)
            .HasPrincipalKey(t=> t.Id)
            .OnDelete(DeleteBehavior.NoAction);

        base.OnModelCreating(builder);
    }
    
    public override DbSet<User>? Users { get; set; }
    public DbSet<ExampleEntity>? ExampleEntities { get; set; }


}

包含查询的错误:

Microsoft.EntityFrameworkCore.Database.Command: Information: Executed DbCommand (31ms) [Parameters=[@__normalizedUserName_0='?' (Size = 256)], CommandType='Text', CommandTimeout='30'] SELECT TOP(1) [a].[Id], [a].[ExampleEntityId], [a].[AccessFailedCount], [a].[BirthDate], [a].[ConcurrencyStamp], [a].[Email], [a].[EmailConfirmed], [a].[JoinedAt], [a].[LockoutEnabled], [a].[LockoutEnd], [a].[Name], [a].[NormalizedEmail], [a].[NormalizedUserName], [a].[PasswordHash], [a].[PhoneNumber], [a].[PhoneNumberConfirmed], [a].[SecurityStamp], [a].[TwoFactorEnabled], [a].[UserName] FROM [AspNetUsers] AS [a] WHERE [a].[NormalizedUserName] = @__normalizedUserName_0 The program '[30000] HomesForAll.exe' has exited with code 3221225477 (0xc0000005) 'Access violation'.

期望的结果是 userManager.FindByNameAsync("Andrew") 找到已经存在的用户记录,return 它使用用户实体并通过抛出异常来停止注册过程。 我尝试更改 AppDbContext 设置,认为这是因为没有用于 ICollection 的列并且模型不匹配,但无济于事。

代码:

public DateTime JoinedAt {
    get { return DateTime.Now; }
    set { JoinedAt = value; }

有一个递归 Setter。

这可能是错误的原因。

尝试:

public DateTime JoinedAt { get; set; } = DateTime.Now;

这是相同的逻辑并使用自动 getter / setters。

背景:

请参阅 https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-properties 了解 属性 get/set 的概述。

要知道的关键是 属性 和字段之间的区别。字段是存储值的地方。 属性 是 Get / Set 之一或两者的方法,用于访问基础字段。

例如:

长版本是:

private DateTime _joinedAt;
public DateTime JoinedAt
{
    get { return _joinedAt; }
    set { _joinedAt = value; }
}

在 C# 中,您可以将上述内容实现为自动属性,只需使用(即,get 或 set 方法本身没有主体):

public DateTime JoinedAt { get; set; }

C# 编译器在后台创建 _joinedAt 字段。

在您的示例中,您没有采用自动属性方法,因此获取和设置方法按编码执行。在您的情况下,JoinedAt.Set 由客户端调用:

user.JoinedAt = {somedate};

然后你 Setter 有效调用

this.JoinedAt = value;

其中 re-invokes Setter 无穷无尽。

这会导致无限 call-stack 和内存故障。这是由您遇到的访问冲突错误报告的。