UserManager.GetUserAsync без отслеживания изменений? - PullRequest
0 голосов
/ 06 февраля 2019

Я использую следующую функцию, чтобы проверить, является ли человек, который хочет получить доступ к какой-либо записи базы данных, владельцем этой записи:

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 голосов
/ 06 февраля 2019

Вы не можете использовать .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();
}

Затем для доступа к услуге AccessGuard в вашемМетод контроллера MVC, сначала зарегистрируйте AccessGuard в Startup следующим образом:

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;

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...