实体框架异步调用阻止UI线程

时间:2016-03-27 08:25:22

标签: wpf mvvm async-await entity-framework-6 mvvm-light

我一直在慢慢尝试将代码从使用操作委托转换为WPF应用程序中的新任务。我喜欢await操作可以在同一方法中运行的事实,大大减少了我需要的方法数量,增强了可读性并减少了维护。话虽这么说,我在调用EF6异步方法时遇到了代码问题。他们似乎都同步运行并阻止我的UI线程。我在代码中使用了以下技术/框架:

作为示例,我有一个LogInViewModel,其命令在我的WPF应用程序上单击一个按钮后执行。这是在构造函数中初始化的命令:

LogInCommand = new RelayCommand(() => ExecuteLogInCommand());

这是命令体:

private async void ExecuteLogInCommand()
{
     // Some code to validate user input

     var user = await _userService.LogIn(username, password);

     // Some code to confirm log in
}

用户服务使用使用MVVM Light的SimpleIoC容器创建的通用存储库对象。 LogIn方法如下所示:

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;
}

我的存储库代码登录:

public static async Task<User> FindUser(this IRepositoryAsync<User> repository, string username)
{
    return await repository.Queryable().Where(u => u.Username == username).SingleOrDefaultAsync();
}

SingleOrDefaultAsync()调用是Entity Framework的异步调用。此代码阻止了我的UI线程。我已阅读Stephen Cleary和其他人关于异步等待和正确使用的多篇文章。我一直尝试使用ConfigureAwait(false),没有运气。我让我的RelayCommand调用使用async await关键字没有运气。我已经分析了代码,返回时间最长的行是SingleOrDefaultAsync()行。其他一切几乎都是瞬间发生的。在我的代码中对DB进行其他异步调用时遇到同样的问题。唯一可以立即修复它的是:

User user = await Task.Run(() =>
{
    return _userService.LogIn(Username, p.Password);
});

但是我知道这不应该是必要的,因为我对数据库的调用是IO绑定而不是CPU绑定。那么,我的应用程序有什么问题,为什么它会阻止我的UI线程?

2 个答案:

答案 0 :(得分:0)

您的RelayCommand不是异步的。

LogInCommand = new RelayCommand(() => ExecuteLogInCommand());

由于没有async / await您的ExecuteLogInCommand将被同步调用。

你必须把它改成

LogInCommand = new RelayCommand(async () => await ExecuteLogInCommand());

这样RelayCommand也称为异步。

答案 1 :(得分:0)

您的dir1LogInaccording to the guidelines应该被称为FindUserLogInAsync)不应该使用UI应该使用所有等待FindUserAsync

但是,在调用真正异步的内容之前,所有调用都是同步的。我想那将是ConfigureAwait(false)

如果将其包装在SingleOrDefaultAsync中会有所不同,那么,出于某种原因,Task.Run必须同步运行。