C # Entity Framework error on async methods
I've seen this before, but I have a different problem.
I have this service class for managing ASP.NET identity roles:
public class RoleService : IRoleService
{
private readonly RoleManager<ApplicationRole> _roleManager;
public RoleService(RoleManager<ApplicationRole> roleManager)
{
this._roleManager = roleManager;
}
public async Task<IdentityResult> CreateAsync(ApplicationRole role)
{
return await this._roleManager.CreateAsync(role);
}
}
As suggested by this question , I use a method CreateAsync
like this to avoid using LINQ foreach
:
private async Task PopulateRoles()
{
var roles = new[] { "A", "B", "C", "D" };
// Used LINQ foreach previously but I coded this way instead to follow the related questions answer
var tasks = roles.Select(role =>
this._roleService.CreateAsync(new ApplicationRole(role)))
.ToList();
await Task.WhenAll(tasks);
}
However, this results in a runtime error await this.PopulateRoles()
.
Entity Framework: There is already an open DataReader associated with this command, which should be closed first.
Searching for this error only leads to a suggestion to add ToList()
LINQ to my selection. How can I fix this?
source to share
The problem lies with RoleManager<T>
, which internally gets one DbContext
, as we can see here :
public class RoleStore<TRole, TContext, TKey> :
IQueryableRoleStore<TRole>,
IRoleClaimStore<TRole>
where TRole : IdentityRole<TKey>
where TKey : IEquatable<TKey>
where TContext : DbContext
{
public RoleStore(TContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
Context = context;
}
}
DbContext
itself cannot handle concurrent calls. An alternative would be to do each of the calls inside foreach
and await
each of them:
private async Task PopulateRoles()
{
var roles = new[] { "A", "B", "C", "D" };
foreach (var role in roles)
{
await _roleService.CreateAsync(new ApplicationRole(role));
}
}
Thus, while you cannot use all roles at the same time, you still use the asynchronous nature of the IO call instead of the blocking synchronous call.
source to share