没有跟踪更改的UserManager.GetUserAsync?

时间:2019-02-06 16:47:27

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

我正在使用以下功能来检查想要访问某些数据库记录的人是否是该记录的所有者:

public class AccessGuard
{
    public async Task<bool> IsOwnerOrHaveRightsAsync(UserManager<ApplicationUser> userManager, ApplicationUser claimant, ClaimsPrincipal User)
    {
        ApplicationUser fullUser = await userManager.GetUserAsync(User);
        if (claimant.Id == fullUser.Id)
        {
            return true;
        }

        return false;
    }
}

它可以工作,但是正如我注意到的那样:ApplicationUser现在已添加到ChangeTracker中。这意味着我以后无法在代码中调用userManager.GetUserAsync,因为出现此错误:

  

无法跟踪实体类型'ApplicationUser'的实例,因为已经跟踪了具有相同键值的{'Id'}的另一个实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。

我通常在访问数据库记录时使用.AsNoTracking(),但是在userManager中没有类似的东西。您将如何解决这个问题?

我正在MVC Controller方法中使用它,如下所示:

if (!await new AccessGuard().IsOwnerOrHaveRightsAsync(_userManager, Post.Author, User))
{
     return Unauthorized();
}

1 个答案:

答案 0 :(得分:1)

您不能将.AsNoTracking()await userManager.GetUserAsync(User);一起使用。或者,您可以执行以下操作:

public class AccessGuard
{
    private readonly ApplicationDbContext _context;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public AccessGuard(ApplicationDbContext context, IHttpContextAccessor httpContextAccessor)
    {
       _httpContextAccessor = httpContextAccessor;
       _context = context;
    }

   public async Task<bool> IsOwnerOrHaveRightsAsync(UserManager<ApplicationUser> userManager, ApplicationUser claimant, ClaimsPrincipal User)
   {
        var loggedInUserId = _httpContextAccessor.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier);
        ApplicationUser fullUser = _context.ApplicationUsers.AsNoTracking()
                                  .FirstOrDefaultAsync(au => au.Id == loggedInUserId);
       if (claimant.Id == fullUser.Id)
       {
           return true;
       }

       return false;
   }
}

然后,您应该在IHttpContextAccessor类中注册Startup,如下所示:

public void ConfigureServices(IServiceCollection services)
{
    services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

    // Or you can also register as follows

    services.AddHttpContextAccessor();
}

然后以MVC控制器方法访问AccessGuard服务,首先在Startup中注册AccessGuard,如下所示:

services.AddScoped<AccessGuard>();

然后在您的控制器方法中:

public  IActionResult Index()
{
     AccessGuard accessGuardService = (AccessGuard) HttpContext.RequestServices.GetService(typeof(AccessGuard));

    // Now call `accessGuardService` service method here

     return View();
}

您还可以按以下方式获得AccessGuard服务:

AccessGuard accessGuardService = HttpContext.RequestServices.GetService<AccessGuard>();

,它需要命名空间using Microsoft.Extensions.DependencyInjection;