C# 调用数据库异步方法而不阻塞ui UWP的最佳实践
我有一个从SQLite数据库获取数据的应用程序。例如,我有一个类似以下的方法:C# 调用数据库异步方法而不阻塞ui UWP的最佳实践,c#,.net,uwp,async-await,C#,.net,Uwp,Async Await,我有一个从SQLite数据库获取数据的应用程序。例如,我有一个类似以下的方法: public async Task<IEnumerable<TaskItem>> GetAllAsync() { using (var context = new NotesContext()) { try { return await context .Tasks
public async Task<IEnumerable<TaskItem>> GetAllAsync()
{
using (var context = new NotesContext())
{
try
{
return await context
.Tasks
.ToListAsync();
}
catch (Exception)
{
return Enumerable.Empty<TaskItem>();
}
}
}
公共异步任务GetAllAsync()
{
使用(var context=new NotesContext())
{
尝试
{
返回等待上下文
.任务
.ToListAsync();
}
捕获(例外)
{
返回可枚举的.Empty();
}
}
}
我通过加载页面时绑定的命令调用此方法:
LoadedCommand = new RelayCommand<TaskItemViewModel>
((task) => GetAllTasksAsync(task));
LoadedCommand=newrelaycommand
((任务)=>GetAllTasksAsync(任务));
以及命令调用的方法:
public async void GetAllTasksAsync(TaskListItemViewModel taskList)
{
ShowTaskListViewProgressRing = true;
Tasks.Clear();
TaskAutoSuggestBoxItems.Clear();
var response = await _dataService
.TaskService
.GetAllAsync()
.ConfigureAwait(false);
var tasks = _mapper.Map<List<TaskItemViewModel>>(response);
if (tasks.Count > 0)
{
var mainTasks = tasks
.Where(t => t.ParentTask == null);
mainTasks.ForEach(t =>
{
if (!tasks.Any(st => st.ParentTask == t.TaskID))
return;
t.SubTasks = new ObservableCollection<TaskItemViewModel>(
tasks
.Where(st => st.ParentTask == t.TaskID)
.OrderBy(st => st.Position));
});
Tasks.AddRange(mainTasks);
TaskAutoSuggestBoxItems
.AddRange(_mapper.Map<IEnumerable<ItemModel>>(mainTasks.OrderBy(t => t.Title)));
}
CurrentTaskList = taskList;
ShowTaskListViewProgressRing = false;
}
公共异步void GetAllTasksAsync(TaskListItemViewModel任务列表)
{
ShowTaskListViewProgressRing=true;
任务。清除();
TaskAutoSuggestBoxItems.Clear();
var response=wait\u数据服务
.任务服务
.GetAllAsync()
.配置等待(错误);
var tasks=\u mapper.Map(响应);
如果(tasks.Count>0)
{
var mainstasks=任务
。其中(t=>t.ParentTask==null);
mainstasks.ForEach(t=>
{
如果(!tasks.Any(st=>st.ParentTask==t.TaskID))
回来
t、 子任务=新的可观察集合(
任务
.Where(st=>st.ParentTask==t.TaskID)
.OrderBy(st=>st.Position));
});
Tasks.AddRange(主任务);
TaskAutoSuggestBoxItems
.AddRange(_mapper.Map(mainstasks.OrderBy(t=>t.Title));
}
CurrentTaskList=任务列表;
ShowTaskListViewProgressRing=false;
}
如果我没有错,GetAllTasksAsync
会被UI线程调用,但是当它到达GetAllAsync().ConfigureAwait(false)
时,它会跳出上下文,然后GetAllAsync
会在线程池上下文中运行,完成后会返回到UI线程并更新视图属性
这种方法正确吗
这种方法正确吗
捕捉异常并假装什么都没发生,这不是最佳做法:
catch (Exception)
{
return Enumerable.Empty<TaskItem>();
}
另外,不返回值(如GetAllTasksAsync
)的异步方法应返回Task
,而不是void
:
public async Task GetAllTasksAsync(TaskListItemViewModel taskList){ ... }
否则,当你打电话时,你就不能等待它了
您对捕获
SynchronizationContext
和ConfigureAwait
的假设是正确的。是TaskAutoSuggestBoxItems
UI控件吗?@JohanP它是绑定到AutoSuggestBoxItemsSource的ObservableCollection
属性,如果您不触摸其中的任何UI控件GetAllTasksAsync
然后使用configureAwait(false)
可以,否则由于未捕获上下文,您将获得异常,并且继续将在线程池线程上运行。@JohanP by ui controls在此上下文中它可能是绑定属性吗?如果这是正确的任务
和任务AutoSuggestBoxItems
被绑定到视图,那么应用程序应该崩溃吧?源属性与UI目标属性不同。您不能从后台线程触摸控件,但可以设置视图模型的源属性。您好,谢谢您,anwser,是的,我知道当前的try-catch不是最好的..,撇开它不谈,因此如果GetAllTasksAsync
应该返回任务,那么我的命令看起来像LoadedCommand=new RelayCommand(async(task)=>await GetAllTasksAsync(task));
在这种情况下,我为什么要等待GetAllTasksAsync?。根据@JohanP的评论,因为我正在触摸在GetAllAsync()配置await(false)之后修改ui的属性
,应用程序应该崩溃,但在我的情况下,它不会崩溃。为什么设置视图模型的源属性会使应用程序崩溃?并且RelayCommand不是异步的。但是任何异步方法都应该返回任务。好的,当我调用var response=wait\u dataService.TaskService.GetAllAsync().configurewait(false)时
ui线程仍然调用GetAllAsync()
的内容,对吗?那么我应该在返回等待上下文.Tasks.toListSync();
中添加ConfigureAwait(false)
,还是在任务.Run()中包装方法的内容?GetAllAsync()
在调用线程上同步执行,直到它遇到等待。异步
/等待
不会导致创建任何新线程。如果有其他问题,请提出新问题。不要在注释字段中提出多个不同的问题。
public async Task GetAllTasksAsync(TaskListItemViewModel taskList){ ... }