我一直在慢慢尝试将我的代码从使用操作委托(delegate)转换为我的 WPF 应用程序中的新任务。我喜欢一个 await 操作可以在同一个方法中运行的事实,大大减少了我需要的方法数量,增强了可读性,并减少了维护。话虽如此,我在调用 EF6 异步方法时遇到了我的代码问题。它们似乎都在同步运行并阻塞了我的 UI 线程。我在我的代码中使用以下技术/框架:
https://genericunitofworkandrepositories.codeplex.com/
例如,我有一个 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() 行。其他一切几乎都是瞬间发生的。在我的代码中对数据库进行其他异步调用时,我遇到了同样的问题。唯一可以立即修复它的是以下内容:
User user = await Task.Run(() =>
{
return _userService.LogIn(Username, p.Password);
});
但我知道这不是必需的,因为我对数据库的调用是 IO 绑定(bind)的,而不是 CPU 绑定(bind)的。那么,我的应用程序出了什么问题,为什么它会阻塞我的 UI 线程?
最佳答案
您的 RelayCommand
不是异步的。
LogInCommand = new RelayCommand(() => ExecuteLogInCommand());
因为没有
async
/await
您的 ExecuteLogInCommand
将被同步调用。你必须把它改成
LogInCommand = new RelayCommand(async () => await ExecuteLogInCommand());
使
RelayCommand
也称为异步。
关于wpf - Entity Framework 异步调用阻塞 UI 线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36245342/