.net - 将 ASP.Net Identity 表链接到用户详细信息表

标签 .net asp.net-core asp.net-identity entity-framework-core asp.net-core-2.1

我正在尝试将我的 Identity 用户表链接到我创建的用于跟踪其他用户信息的用户详细信息表。该用户详细信息表称为 UserProfile。

我遇到了这个链接,但它在 .NET Core 2.1 中不起作用:
Link ASP.NET Identity users to user detail table

这是我目前所拥有的:

public class ApplicationUser : IdentityUser
{

    [Key]
    public override string Id { get; set; }

    [ForeignKey("Id")]
    public virtual UserProfile UserProfile { get; set; }

}

[Table("UserProfile")]
public class UserProfile
{
    [Key, ForeignKey("User")]
    public string UserId { get; set; } // UserId (Primary key) 
    public string UserName { get; set; } // UserName 
    public string FirstName { get; set; } // FirstName
    public string LastName { get; set; } // LastName

    //[ForeignKey("Id")]
    public virtual ApplicationUser User { get; set; }
}

但是,在我调用的代码中的其他地方:
var user = await _userMgr.FindByNameAsync(model.UserName);

并且 user.UserProfile 为空。

我尝试了很多数据注释的组合,甚至连流畅的api都无济于事。
   modelBuilder.Entity<ApplicationUser>()
       .HasOne(c => c.UserProfile)
       .WithOne(t => t.User)
       .HasForeignKey<UserProfile>(b => b.UserId);

我也尝试打开延迟加载,但这甚至无法加载该属性。

有谁知道如何在 .Net Core 2.1 中做到这一点?

谢谢

最佳答案

您的主要问题只是 UserManager没有包含相关实体的功能,例如您的 UserProfile .因此,您有两个选择:

  • 直接使用您的上下文。然后你可以急切地加载你的 UserProfile随着ApplicationUser例如,只需对数据库进行一次查询:
    var user = await _context.Users.Include(x => x.UserProfile).SingleOrDefaultAsync(x => x.UserName ==  model.UserName);
    
  • 您可以显式加载相关 UserProfile反而。但是,这将导致额外的查询,总共有两个:一个获取用户,一个获取相关配置文件:
    await _context.Entry(user).Reference(x => x.UserProfile).LoadAsync();
    

  • 然而,坦率地说,你不应该有 UserProfile根本。 ASP.NET Identity 与 ASP.NET Membership 不同。对于后者,您必须有一个单独的 UserProfile因为 Membership 中的“用户”是不可扩展的。在 Identity 中,用户是可扩展的,因此如果您想要关于它的其他配置文件信息,只需将其添加到类中:
    public class ApplicationUser : IdentityUser
    {
        public string FirstName { get; set; } // FirstName
        public string LastName { get; set; } // LastName
    }
    

    请注意,我也在这里修剪了很多杂物。覆盖 Id 毫无意义然后让它自动实现。此外,您显然不需要 UserName属性(property)来自 UserProfile因为 IdentityUser已经有了,这当然意味着您的 ApplicationUser也有。

    更新

    用户数据的持久化方式不一定会影响它是否可以声明。换句话说,您不必将数据逐字保存为声明,以便将其作为声明访问。仅源自 UserClaimsPrincipalFactory<TUser> , 覆盖 CreateAsync ,然后将其注册到服务集合作为范围。
    public class MyClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser>
    {
        public MyClaimsPrincipalFactory(UserManager<TUser> userManager, IOptions<IdentityOptions> optionsAccessor)
            : base(userManager, optionsAccessor)
        {
        }
    
        public async override Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
        {
            var principal = await base.CreateAsync(user);
            ((ClaimsIdentity)principal.Identity).AddClaims(new[]
            {
                new Claim(ClaimTypes.GivenName, user.FirstName),
                new Claim(ClaimTypes.Surname, user.LastName),
                // etc.
            });
    
            return principal;
        }
    }
    

    然后在 ConfigureServices :
    services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, MyClaimsPrincipalFactory>();
    

    关于.net - 将 ASP.Net Identity 表链接到用户详细信息表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51996859/

    相关文章:

    c# - LINQ 是否缓存计算值?

    c# - 准确的 "Sieve of Erathostenes"在C#中判断BigInteger的素数

    c# - WCF 数据服务 : 400 Bad Request when saving lots of changes

    azure - 如何将控制台应用程序(来自 asp.net 5 的包)发布为 Azure Web 作业

    entity-framework - 使用 Azure 表存储进行代码优先和身份验证

    c# - 登录后如何返回之前的网址? ( Ajax )

    asp.net - EF 是否在 DbContext 的不同实例之间缓存实体?

    ubuntu - 在 Ubuntu 上创建的红隼服务因错误而停止 (code=exited, status=200/CHDIR)

    unit-testing - 替换 WebApplicationFactory 中的 DbContext 进行单元测试

    c# - 从模拟的 ApplicationUserManager.Users 返回用户