3

I am using FluentValidation to validate the objects. I am simply checking checking whether the user exists in database or not. In my case, DbContext.Entity.Find works just fine but DbContext.Entity.FindAsync never returns.

Please refer to the below source code where it is happening.

    public class ChangeStatusOfUserCommandValidator : AbstractValidator<ChangeStatusOfUserCommand>
{
    private readonly FieldSellDbContext dbContext;
    private ChangeStatusOfUserCommandValidator()
    { }

    public ChangeStatusOfUserCommandValidator(FieldSellDbContext databaseContext)
    {
        dbContext = databaseContext;
        RuleFor(u => u.UserId).NotEmpty();
        RuleFor(u => u.UserId).MustAsync(UserExists).WithMessage("Provided user id already exists in the database.");
    }

    public async Task<bool> UserExists(int value, CancellationToken cancellationToken)
    {
        var user = await dbContext.Users.FindAsync(value, cancellationToken);
        //var user = dbContext.Users.Find(value); --Works fine even in async method
        return user != null;
    }
}

Thanks

Kashif
  • 31
  • 1
  • Which DBMS you are using? Is it possible to try your code with e.g. `sqlite`? – Alex Yu Feb 02 '19 at 10:57
  • I am using SqlExpress. I just tried that FirstOrDefaultAsync method and it is also working fine whereas FindAsync is not working. – Kashif Feb 02 '19 at 12:47
  • Can you show how do you call `UserExists`? I hope you do not forget to `await` its result? – Alex Yu Feb 02 '19 at 12:52
  • I am calling the UserExists method in the following statement: RuleFor(u => u.UserId).MustAsync(UserExists) – Kashif Feb 03 '19 at 05:29

1 Answers1

0

Your problem is almost certainly further up your call stack, where the code is calling Task<T>.Result, Task.Wait(), Task.GetAwaiter().GetResult(), or some similar blocking method. If your code blocks on asynchronous code in a single-threaded context (e.g., on a UI thread), it can deadlock.

The proper solution is to use async all the way; that is, use await instead of blocking on asynchronous code. Fluent validation has an asynchronous workflow (e.g., ValidateAsync, MustAsync), so you'll need to be sure to use that rather than the synchronous APIs.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Hi Stephen, my thoughts were same to ensure that no call is synchronous and async was used for all the calls. It is a method in WebAPI so there is no role of UI. Also, i am using MedatR library and CQRS pattern for this api. Call to this validator is automatically done by MediatR which is working for all other async calls. for more information, FirstOrDefaultAsync is working fine as well. – Kashif Feb 03 '19 at 05:51
  • 1
    @Kashif That is strange, because `FindAsync` consists of synchronous `FindTracked` call (same as `Find`) and eventually (in case not found in the local cache) followed by `FirstOrDefaultAsync`. – Ivan Stoev Feb 03 '19 at 12:27