Entity Framework async call blocking UI thread

async-await entity-framework-6 mvvm mvvm-light wpf

Question

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?

1
1
3/27/2016 8:44:03 AM

Popular Answer

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.

0
3/27/2016 4:14:25 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow