I have been slowly trying to convert my code from using action delegates to the new Tasks in my WPF application. I like the fact that an await operation can run in the same method, greatly reducing the number of methods I need, enhancing readability, and reducing maintenance. That being said, I am having a problem with my code when calling EF6 async methods. They all seem to run synchronously and are blocking my UI thread. I use the following technologies/frameworks in my code:
As an example, I have a LogInViewModel, with a command that executes after a button is clicked on my WPF application. Here is the command as initialized in the constructor:
LogInCommand = new RelayCommand(() => ExecuteLogInCommand());
Here is the command body:
private async void ExecuteLogInCommand()
{
// Some code to validate user input
var user = await _userService.LogIn(username, password);
// Some code to confirm log in
}
The user service uses a generic repository object that is created using MVVM Light's SimpleIoC container. The LogIn method looks like this:
public async Task<User> LogIn(string username, string password)
{
User user = await _repository.FindUser(username);
if (user != null && user.IsActive)
{
// Some code to verify passwords
return user;
}
return null;
}
And my repository code to log in:
public static async Task<User> FindUser(this IRepositoryAsync<User> repository, string username)
{
return await repository.Queryable().Where(u => u.Username == username).SingleOrDefaultAsync();
}
The SingleOrDefaultAsync() call is Entity Framework's async call. This code is blocking my UI thread. I have read multiple articles from Stephen Cleary and others about async await and proper use. I have tried using ConfigureAwait(false) all the way down, with no luck. I have made my RelayCommand call use the async await keywords with no luck. I have analyzed the code and the line that takes the longest to return is the SingleOrDefaultAsync() line. Everything else happens almost instantaneously. I have the same problem when making other async calls to the DB in my code. The only thing that fixes it right away is the following:
User user = await Task.Run(() =>
{
return _userService.LogIn(Username, p.Password);
});
But I understand this should not be necessary since the call I am making to the database is IO bound and not CPU bound. So, what is wrong with my application and why is it blocking my UI thread?
Your LogIn
and FindUser
(which, according to the guidelines, should be called LogInAsync
and FindUserAsync
) which are not supposed to work with the UI should use ConfigureAwait(false)
on all awaits.
However all calls are synchronous until something really asynchronous is called. I suppose that would be SingleOrDefaultAsync
.
If wrapping it in Task.Run
makes such a difference, then, for some reason, SingleOrDefaultAsync
must be running synchronously.