【问题标题】:A second operation started on this context before a previous operation completed. Async method on interface在前一个操作完成之前,第二个操作在此上下文中开始。接口上的异步方法
【发布时间】:2018-03-08 23:19:31
【问题描述】:

当我尝试从我实现的接口SaveChangesAsync() 时遇到错误。此界面上的所有其他方法似乎都可以正常工作。我在给出错误的任务和每个人IsCompleted 之前调试了每一项任务。我是新手,所以请告诉我我在这里做错了什么。

UserController 只是构造函数

private readonly IUserRepository _userRepository;
private readonly IRoleRepository _roleRepository;

public UserController(IUserRepository userRepository,IRoleRepository roleRepository)
{
      _userRepository = userRepository;
      _roleRepository = roleRepository;
}

UserController/Edit

public async Task<IActionResult> Edit(string id, EditViewModel model)
        {
            ApplicationUser user = new ApplicationUser();
            List<IdentityRole> listaRoles = new List<IdentityRole>();
            IdentityRole Role = new IdentityRole();
            List<IdentityRole> listaSelectedRoles = new List<IdentityRole>();

            //Atribuir o nomeUtilizador ao modelo do Post
            var modelTemp = await base.CreateModel<EditViewModel>(_userRepository);
            Task taskModel = base.CreateModel<EditViewModel>(_userRepository);
            await Task.WhenAll(taskModel);
            bool test = taskModel.IsCompleted; //to debug: test = true;

            model.NomeUtilizador = modelTemp.NomeUtilizador;
            modelTemp = null;

            //buscar o utilizador com o id à base de dados
            user = await _userRepository.FindByIDAsync(id);
            var boo = _userRepository.FindByIDAsync(id).IsCompleted;    //to debug: boo = true;

            //Buscar roles da bd para uma lista
            var task = _roleRepository.ToListAsync();
            listaRoles = await task;
            var t = task.IsCompleted; //to debug: t = true;

            (...)

            if (ModelState.IsValid)
            {
                try
                {
                    (...)
                    //Adicionar/remover roles a cada utilizador
                    foreach (var role in listaRoles)
                    {
                        await _userRepository.RemoveFromRoleAsync(user, role.Name); //tested here: true aswell

                        foreach(var selectedRole in listaSelectedRoles)
                        {
                            if (role.Id == selectedRole.Id)
                            {
                               await _userRepository.AddToRoleAsync(user, selectedRole.Name);   //tested here: true aswell
                            }
                        }
                    }
                    user.Nome = model.Nome;
                    user.Email = model.Email;
                    user.UserName = model.Email;
                    user.PhoneNumber = model.Telemovel;

                    await _userRepository.UpdateAsync(user); //error
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!await ApplicationUserExists(user.Id))
                    {
                        return NotFound();
                    }
                    else
                    {
                        throw;
                    }
                }
                return RedirectToAction(nameof(Index));
            }
            return View(model);
        }

IUserRepository

public interface IUserRepository : IDisposable
    {
        Task<List<ApplicationUser>> ToListAsync();
        Task<ApplicationUser> FindByIDAsync(string userId);
        Task<ApplicationUser> FindByNameAsync(string userName);
        Task<IList<string>> GetRolesAsync(ApplicationUser user);
        Task AddToRoleAsync(ApplicationUser user, string roleName);
        Task RemoveFromRoleAsync(ApplicationUser user, string roleName);
        Task<bool> AnyAsync(string userId);
        Task AddAsync(ApplicationUser user);
        Task DeleteAsync(string userId);
        void Update(ApplicationUser user);
        Task SaveChangesAsync();
        Task UpdateAsync(ApplicationUser user);
    }

UserRepository不是所有节省空间的方法

public class UserRepository : IUserRepository
    {
        private readonly ApplicationDbContext _context;
        private readonly UserManager<ApplicationUser> _userManager;

        public UserRepository(ApplicationDbContext context, UserManager<ApplicationUser> userManager)
        {
            _context = context;
            _userManager = userManager;
        }

        public Task<ApplicationUser> FindByIDAsync(string userId)
        {
            return _context.ApplicationUser.FindAsync(userId);
        }

        public Task<ApplicationUser> FindByNameAsync(string userName)
        {
            return _context.ApplicationUser.SingleOrDefaultAsync(m => m.UserName == userName);
        }

        public Task<List<ApplicationUser>> ToListAsync()
        {
            return _context.ApplicationUser.ToListAsync();
        }

        public Task AddAsync(ApplicationUser user)
        {
            _context.ApplicationUser.AddAsync(user);
            return _context.SaveChangesAsync();
        }

        public Task<IList<string>> GetRolesAsync(ApplicationUser user)
        {
            return _userManager.GetRolesAsync(user);
        }

        public Task AddToRoleAsync(ApplicationUser user, string roleName)
        {
            _userManager.AddToRoleAsync(user, roleName);
            return _context.SaveChangesAsync();
        }

        public Task RemoveFromRoleAsync(ApplicationUser user, string roleName)
        {
            _userManager.RemoveFromRoleAsync(user, roleName);
            return _context.SaveChangesAsync();
        }



        public Task UpdateAsync(ApplicationUser user)
        {
            _context.Entry(user).State = EntityState.Modified;
            return _context.SaveChangesAsync();
        }
    }

就像我说的,我调试了所有其他方法及其:Status = RanToCompletion。 谢谢。

【问题讨论】:

  • 你能发布异常跟踪吗?

标签: c# asp.net-mvc async-await


【解决方案1】:

您的“存储库”中有几个方法可以启动异步操作,但不等待它们完成。所以你需要修复这些方法:

public async Task AddAsync(ApplicationUser user)
{
    // need to await this one
    await _context.ApplicationUser.AddAsync(user);
    await _context.SaveChangesAsync();
}

public async Task AddToRoleAsync(ApplicationUser user, string roleName)
{
    // same story
    await _userManager.AddToRoleAsync(user, roleName);
    await _context.SaveChangesAsync();
}

public async Task RemoveFromRoleAsync(ApplicationUser user, string roleName)
{
    // same story
    await _userManager.RemoveFromRoleAsync(user, roleName);
    await _context.SaveChangesAsync();
}

【讨论】:

  • 是的,当我创建这些方法时,我认为我需要某种return。为什么我不需要返回 Task ?非常感谢。
  • @LeonardoHenriques 好吧,您似乎了解async 的工作原理。例如,您的代码中的 Edit 方法返回 `Task`,但实际上您从中返回了 View,即 IActionResult。同样的故事:因为方法标有async - 它已经总是返回Task,所以你不需要显式返回。如果异步方法返回Task&lt;SomeType&gt;,如Task&lt;int&gt; - 那么您需要返回值:return 1;,但不是Task,因为它已经始终是Task(因为您将方法标记为async)。
  • @LeonardoHenriques 请注意,您的其他方法是正确的。如果您在方法中所做的唯一事情是调用另一个异步方法 - 您不需要将任何内容标记为 async - 只需返回该其他方法的结果。例如:Task&lt;ApplicationUser&gt; FindByIDAsync(string userId) { return _context.ApplicationUser.FindAsync(userId);} - 正确。 async Task&lt;ApplicationUser&gt; FindByIDAsync(string userId) { return await _context.ApplicationUser.FindAsync(userId);} - 不正确(好吧,它会起作用,但没有理由这样做)。
  • 我只需要将一个方法标记为async,当它有多个异步方法时,他们就可以await? @Evk
  • @LeonardoHenriques 当有多个异步方法或者你只有一个,但这不是你在那个方法中做的最后一件事。例如async Task Method() {await DoSomething(); DoSomethingElse()} Task Method() {return DoSomething();}
【解决方案2】:

尝试在 UserRepository 上更改此设置:

    public Task UpdateAsync(ApplicationUser user)
    {
        _context.Entry(user).State = EntityState.Modified;
        return _context.SaveChangesAsync();
    }

到这里,用于返回 _context.SaveChangesAsync() 的 int 值:

    public async Task<int> UpdateAsync(ApplicationUser user)
    {
            _context.Entry(user).State = EntityState.Modified;
            return await _context.SaveChangesAsync();               
    }

【讨论】:

  • 哦,一开始我也想这么做,但是不知道要返回什么类型。为什么&lt;int&gt;寿?
  • 因为,如果你看到智能感知,函数 _context.SaveChangesAsync() 返回受影响的行数EF saveChangesAsynk
猜你喜欢
  • 2017-03-14
  • 1970-01-01
  • 1970-01-01
  • 2018-05-22
  • 2014-12-08
  • 2021-05-04
  • 1970-01-01
  • 1970-01-01
  • 2022-01-01
相关资源
最近更新 更多