Reputation: 123
I am facing with issue caused by database using EF Core. In short: every asynchronous operation on database is throwing an exception: "Task was canceled.". I was tried to use another scope from IServiceProvider to create context and run async code then, but first call of async method is closing the request and code is already running, but request has been ended. There is no difference between executing code in controller or another place in code. To be more detailed, these kinds of issues have started after I extended my DbContext with 'Identity' entity and made relation with 'Profile' entity. I can't understand, what is the reason of this application behaviour, even if synchronously operation on database works well.
The example of not working code is:
try
{
var userExists = await _userManager.Users
.AnyAsync(x => x.Email == request.Email, cancellationToken: cancellationToken);
...
}
catch(TaskCanceledException ex)
{
// exception details
}
My context looks like follows:
public class ApplicationContext : IdentityDbContext<Identity, IdentityRole<Guid>, Guid>
{
...,
public DbSet<Profile> Profiles { get; set;
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Ignore<IdentityUserLogin<Guid>>();
builder.Ignore<IdentityUserToken<Guid>>();
builder.Entity<IdentityUserClaim<Guid>>().ToTable("IdentitiesClaims");
builder.Entity<IdentityRoleClaim<Guid>>().ToTable("IdentitiesRoleClaims");
builder.Entity<IdentityRole<Guid>>().ToTable("IdentitiesRoles");
builder.Entity<IdentityUserRole<Guid>>().ToTable("IdentitiesUserRoles");
builder.Entity<Identity>.ToTable("Identities");
builder.Entity<Identity>.HasIndex(x => new { x.Id, x.Email
}).IsUnique();
builder.Entity<Identity>.Ignore(x => x.AccessFailedCount);
builder.Entity<Identity>.Ignore(x => x.LockoutEnabled);
builder.Entity<Identity>.Ignore(x => x.LockoutEnd);
builder.Entity<Identity>.Ignore(x => x.PhoneNumber);
builder.Entity<Identity>.Ignore(x => x.TwoFactorEnabled);
builder.Entity<Identity>.Ignore(x => x.PhoneNumberConfirmed);
builder.Entity<Identity>.Ignore(x => x.UserName);
builder.Entity<Profile>.HasKey(x => x.Id);
}
}
Identity entity:
public sealed class Identity : IdentityUser<Guid>
{
public IdentityType IdentityType { get; set; }
public string RefreshToken { get; set; }
public DateTime CreatedOn { get; set; }
public Profile Profile { get; set; }
private Identity() { }
public Identity(Guid id, string email, string passwordHash,
IdentityType identityType, string refreshToken)
{
this.Id = id;
this.Email = email;
this.UserName = email;
this.EmailConfirmed = true;
this.NormalizedEmail = email.ToUpper();
this.NormalizedUserName = this.NormalizedEmail;
this.PasswordHash = passwordHash;
this.IdentityType = identityType;
this.RefreshToken = refreshToken;
this.CreatedOn = DateTime.UtcNow;
}
public static Identity FromDomain(Domain.Identity.Identity identity, string refreshToken)
=> new(identity.Id, identity.Email, identity.PasswordHash, identity.IdentityType, refreshToken);
}
Profile entity:
public class Profile : IEntity<int>
{
public int Id { get; protected set; }
public string FirstName { get; protected set; }
public string LastName { get; protected set; }
public DateTime DateOfBirth { get; protected set; }
public Guid IdentityId { get; protected set; }
protected Profile() { }
public Profile(string firstName, string lastName,
DateTime dateOfBirth, Guid? identityId = null, int? id = null)
{
this.FirstName = firstName;
this.LastName = lastName;
this.DateOfBirth = dateOfBirth;
if (id.HasValue)
{
this.Id = id.Value;
}
if (identityId.HasValue)
{
this.IdentityId = identityId.Value;
}
}
}
What could be the reason of throwing TaskCanceledException? How can I run database operations asynchronously?
@Edit - 15:34 My minimal reproducible example is: Program.cs -
public static async Task Main(string[] args)
{
var host = Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webHost =>
{
webHost.CaptureStartupErrors(true)
.UseStartup<Startup>()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseKestrel();
}).Build();
await host.RunAsync();
}
IdentityController -
public async Task<IActionResult> BeginUserCreation(string email)
{
await _commandBus.Send(new BeginUserCreation(email));
return this.Ok();
}
CommandBus -
public Task Send<TCommand>(TCommand command) where TCommand : ICommand
=> Mediator.Send(command);
CommandHandler -
public interface ICommandHandler<in TCommand> : IRequestHandler<TCommand>
where TCommand : ICommand { }
BeginUserCreationHandler -
public async Task<Unit> Handle(BeginUserCreation request, CancellationToken cancellationToken)
{
try
{
var userExists = await _userManager.Users
.AnyAsync(x => x.Email == request.Email, cancellationToken: cancellationToken);
...
}
catch(TaskCanceledException ex)
{
return Unit.Value;
}
}
Upvotes: 0
Views: 448
Reputation: 123
Problem solved. As said @mjwills - I forgot to await asynchronous operation. Invoke method in one of delegates wasn't awaited. After _next delegate was awaited, the issue has been solved.
Upvotes: 1