在 ViewModel 中调用的异步方法导致死锁
Async method that calls in ViewModel causes deadlock
我向 Github Api 发出请求,所以我有异步方法,这些方法可以完成这项工作。在此之前,我总是在方法中调用它们,从命令(实际上是 DelegateCommand)调用。但现在我想在 ViewModel 中做请求,因为我需要在页面上显示列表。我正在使用 Prism 连接视图和视图模型。
因为我不能使视图模型异步,所以我不能使用等待词,所以我尝试做一些事情,比如从任务中获取结果,或者 task.wait。但是有了这个,我得到了相同的结果。我的应用程序停止在请求时以白色显示工作。我阅读了一些相关信息,我知道在非异步方法中调用异步方法是不好的,它会导致死锁,但我不知道该怎么做。而且我认为死锁导致应用程序停止工作。
这是应用死机的方法:
public async Task<IEnumerable<RepositoryModel>> GetRepositoriesAsync()
{
try
{
var reposRequest = new RepositoryRequest { Sort = RepositorySort.FullName };
var gitHubRepos = await _gitHubClient.Repository.GetAllForCurrent(reposRequest); //async request, don't say about name convention, it is not my method.
var gitRemoteRepos = new List<RepositoryModel>();
foreach ( var repository in gitHubRepos )
{
var repos = new RepositoryModel();
repos.RepositoryTypeIcon = GetRepositoryTypeIcon(repository);
gitRemoteRepos.Add(repos);
}
return gitRemoteRepos;
}
catch ( WebException ex )
{
throw new Exception("Something wrong with internet connection, try to On Internet " + ex.Message);
}
catch ( Exception ex )
{
throw new Exception("Getting repos from github failed! " + ex.Message);
}
}
这是视图模型:
public class RepositoriesPageViewModel : BindableBase
{
private INavigationService _navigationService;
private readonly Session _session;
public ObservableCollection<RepositoryModel> Repositories { get; }
private readonly RepositoriesManager _repositoriesManager;
public RepositoriesPageViewModel(INavigationService navigationService, ISecuredDataProvider securedDataProvider)
{
_navigationService = navigationService;
var token = securedDataProvider.Retreive(ConstantsService.ProviderName, UserManager.GetLastUser());
_session = new Session(UserManager.GetLastUser(), token.Properties.First().Value);
var navigationParameters = new NavigationParameters { { "Session", _session } };
_repositoriesManager = new RepositoriesManager(_session);
var task = _repositoriesManager.GetRepositoriesAsync();
//task.Wait();
Repositories = task.Result as ObservableCollection<RepositoryModel>;
}
}
我建议使用我的 NotifyTask<T>
type, which provides a data-bindable wrapper around Task<T>
. I explain this pattern more completely in my article on async MVVM data binding。
public class RepositoriesPageViewModel : BindableBase
{
private INavigationService _navigationService;
private readonly Session _session;
public NotifyTask<ObservableCollection<RepositoryModel>> Repositories { get; }
private readonly RepositoriesManager _repositoriesManager;
public RepositoriesPageViewModel(INavigationService navigationService, ISecuredDataProvider securedDataProvider)
{
_navigationService = navigationService;
var token = securedDataProvider.Retreive(ConstantsService.ProviderName, UserManager.GetLastUser());
_session = new Session(UserManager.GetLastUser(), token.Properties.First().Value);
var navigationParameters = new NavigationParameters { { "Session", _session } };
_repositoriesManager = new RepositoriesManager(_session);
Repositories = NotifyTask.Create(GetRepositoriesAsync());
}
}
private async Task<ObservableCollection<RepositoryModel>> GetRepositoriesAsync()
{
return new ObservableCollection<RepositoryModel>(await _repositoriesManager.GetRepositoriesAsync());
}
请注意,使用这种方法,您的数据绑定将使用 Repositories.Result
来访问实际集合。其他属性也可用,最值得注意的是 Repositories.IsCompleted
和 Respositories.IsNotCompleted
用于 showing/hiding 个忙碌的微调器。
我向 Github Api 发出请求,所以我有异步方法,这些方法可以完成这项工作。在此之前,我总是在方法中调用它们,从命令(实际上是 DelegateCommand)调用。但现在我想在 ViewModel 中做请求,因为我需要在页面上显示列表。我正在使用 Prism 连接视图和视图模型。 因为我不能使视图模型异步,所以我不能使用等待词,所以我尝试做一些事情,比如从任务中获取结果,或者 task.wait。但是有了这个,我得到了相同的结果。我的应用程序停止在请求时以白色显示工作。我阅读了一些相关信息,我知道在非异步方法中调用异步方法是不好的,它会导致死锁,但我不知道该怎么做。而且我认为死锁导致应用程序停止工作。 这是应用死机的方法:
public async Task<IEnumerable<RepositoryModel>> GetRepositoriesAsync()
{
try
{
var reposRequest = new RepositoryRequest { Sort = RepositorySort.FullName };
var gitHubRepos = await _gitHubClient.Repository.GetAllForCurrent(reposRequest); //async request, don't say about name convention, it is not my method.
var gitRemoteRepos = new List<RepositoryModel>();
foreach ( var repository in gitHubRepos )
{
var repos = new RepositoryModel();
repos.RepositoryTypeIcon = GetRepositoryTypeIcon(repository);
gitRemoteRepos.Add(repos);
}
return gitRemoteRepos;
}
catch ( WebException ex )
{
throw new Exception("Something wrong with internet connection, try to On Internet " + ex.Message);
}
catch ( Exception ex )
{
throw new Exception("Getting repos from github failed! " + ex.Message);
}
}
这是视图模型:
public class RepositoriesPageViewModel : BindableBase
{
private INavigationService _navigationService;
private readonly Session _session;
public ObservableCollection<RepositoryModel> Repositories { get; }
private readonly RepositoriesManager _repositoriesManager;
public RepositoriesPageViewModel(INavigationService navigationService, ISecuredDataProvider securedDataProvider)
{
_navigationService = navigationService;
var token = securedDataProvider.Retreive(ConstantsService.ProviderName, UserManager.GetLastUser());
_session = new Session(UserManager.GetLastUser(), token.Properties.First().Value);
var navigationParameters = new NavigationParameters { { "Session", _session } };
_repositoriesManager = new RepositoriesManager(_session);
var task = _repositoriesManager.GetRepositoriesAsync();
//task.Wait();
Repositories = task.Result as ObservableCollection<RepositoryModel>;
}
}
我建议使用我的 NotifyTask<T>
type, which provides a data-bindable wrapper around Task<T>
. I explain this pattern more completely in my article on async MVVM data binding。
public class RepositoriesPageViewModel : BindableBase
{
private INavigationService _navigationService;
private readonly Session _session;
public NotifyTask<ObservableCollection<RepositoryModel>> Repositories { get; }
private readonly RepositoriesManager _repositoriesManager;
public RepositoriesPageViewModel(INavigationService navigationService, ISecuredDataProvider securedDataProvider)
{
_navigationService = navigationService;
var token = securedDataProvider.Retreive(ConstantsService.ProviderName, UserManager.GetLastUser());
_session = new Session(UserManager.GetLastUser(), token.Properties.First().Value);
var navigationParameters = new NavigationParameters { { "Session", _session } };
_repositoriesManager = new RepositoriesManager(_session);
Repositories = NotifyTask.Create(GetRepositoriesAsync());
}
}
private async Task<ObservableCollection<RepositoryModel>> GetRepositoriesAsync()
{
return new ObservableCollection<RepositoryModel>(await _repositoriesManager.GetRepositoriesAsync());
}
请注意,使用这种方法,您的数据绑定将使用 Repositories.Result
来访问实际集合。其他属性也可用,最值得注意的是 Repositories.IsCompleted
和 Respositories.IsNotCompleted
用于 showing/hiding 个忙碌的微调器。