【发布时间】:2016-07-14 17:00:52
【问题描述】:
我一直在慢慢尝试将我的代码从使用操作委托转换为我的 WPF 应用程序中的新任务。我喜欢一个 await 操作可以在同一个方法中运行的事实,大大减少了我需要的方法数量,增强了可读性,并减少了维护。话虽如此,我在调用 EF6 异步方法时遇到了我的代码问题。它们似乎都在同步运行并阻塞了我的 UI 线程。我在代码中使用了以下技术/框架:
- .NET 框架 4.5
- WPF
- MVVM Light 5.2
- 通用工作单元/存储库框架 v3.3.5 https://genericunitofworkandrepositories.codeplex.com/
- 实体框架 6.1.1
- SQL Server 2008 R2 Express
例如,我有一个 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() 调用是实体框架的异步调用。这段代码阻塞了我的 UI 线程。我已经阅读了 Stephen Cleary 和其他人关于异步等待和正确使用的多篇文章。我一直尝试使用 ConfigureAwait(false),但没有运气。我已经让我的 RelayCommand 调用使用了 async await 关键字,但没有成功。我已经分析了代码,返回时间最长的行是 SingleOrDefaultAsync() 行。其他一切几乎都是瞬间发生的。在我的代码中对数据库进行其他异步调用时,我遇到了同样的问题。唯一能立即修复它的是:
User user = await Task.Run(() =>
{
return _userService.LogIn(Username, p.Password);
});
但我知道这不是必需的,因为我对数据库的调用是 IO 绑定的,而不是 CPU 绑定的。那么,我的应用程序出了什么问题,为什么它会阻塞我的 UI 线程?
【问题讨论】:
-
存储库类中的
.Queryable()到底是什么?你怎么称呼它?IRepositoryAsync<User>是否继承自其他接口以及它的具体实现是什么 -
@Tseng Queriable() 只返回底层用户数据库集,您可以对其应用任何实体框架方法调用。 IRepositoryAsync
是 Generic Repository/UnitOfWork 框架提供的接口。它还提供了 EF6 实现。我没有在其中添加任何代码,因为它很广泛。我提供了上面的链接,所以如果你喜欢的话,你可以看看它。谢谢! -
您的模式对我来说看起来不错,一些建议:将生成时的语法缩短为
new RelayCommand;您不需要() =>部分。此外,如果您不修改返回的对象,您可以在存储库代码中删除async和await关键字。通过这个小的更改,您将保存在这种情况下不必要的任务对象的生成。对于您的async问题:您可以尝试在IRepositoryAsync<>上使用Select方法,而不是Queryable()。
标签: wpf mvvm async-await entity-framework-6 mvvm-light