使用带有EF Core的UserManager进行预先加载

时间:2016-10-03 17:40:43

标签: c# asp.net-core entity-framework-core

目前有ApplicationUser类包含一些自定义属性,例如:

public class ApplicationUser : IdentityUser
{
    public string Name { get; set; }
    public List<Content> Content { get; set; }
}

我想让当前记录的用户获得相关数据列表(Content属性)。

在我的控制器中,如果我把:

Applicationuser user = await _userManager.GetUserAsync(HttpContext.User);

我获取了已登录的用户,但没有任何相关数据。 但是,如果我使用ApplicationDbContext检索当前用户,如下所示,我可以检索相关数据:

ApplicationUser user = await _userManager.GetUserAsync(HttpContext.User);
ApplicationUser userWithContent = _context.Users.Include(c => c.Content).Where(u => u.Id == user.Id).ToList();

但这对我来说似乎不正确!

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

检查[UserManager][1]的源代码,GetUserAsync将最终调用FindByIdAsync,这将由IUserStore实现提供。查看问题中的源代码,很有可能使用EFCore作为IUserStore实现。

在使用EFCore的情况下,提到here不能将Findinclude结合使用,所以我请您做好准备,急切地加载问题,实际上正确。

答案 1 :(得分:0)

如果每个请求中都需要这些属性,则有一种更好的方式来获取它们,而无需在每个请求中查询数据库。

您可以通过编写自己的Claims并从IUserClaimsPrincipalFactory<TUser>中读取它们来将这些属性存储为HttpContext.User

public class CustomUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser>
{
    public CustomUserClaimsPrincipalFactory(UserManager<ApplicationUser> userManager, IOptions<IdentityOptions> optionsAccessor)
        : base(userManager, optionsAccessor)
    {

    }

    protected async override Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user)
    {
        ClaimsIdentity identity = await base.GenerateClaimsAsync(user);
        identity.AddClaim(new Claim("Name", user.Name));

        for (int i = 0; i < user.Content.Count; i++)
        {
            string content = Newtonsoft.Json.JsonConvert.SerializeObject(user.Content[i]);
            identity.AddClaim(new Claim("Content", content));
        }

        return identity;
    }
}

还需要将其注册到服务集合

services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, CustomUserClaimsPrincipalFactory>();

您可以使用此代码访问这些属性

string name = httpContext.User.FindFirstValue("Name");

List<Content> contents = new List<Content>();
foreach (Claim claim in httpContext.User.FindAll("Content"))
{
    Content content = Newtonsoft.Json.JsonConvert.DeserializeObject<Content>(claim.Value);
    contents.Add(content);
};