在不阻止ui UWP的情况下调用数据库异步方法的最佳实践

时间:2018-08-22 01:56:59

标签: c# .net uwp async-await

我有一个从SQLite数据库获取一些数据的应用程序。例如,我有一种类似于以下方法的方法:

public async Task<IEnumerable<TaskItem>> GetAllAsync()
{
    using (var context = new NotesContext())
    {
        try
        {
            return await context
                .Tasks
                .ToListAsync();
        }
        catch (Exception)
        {
            return Enumerable.Empty<TaskItem>();
        }
    }
}

我从页面加载时绑定的命令中调用此方法:

LoadedCommand = new RelayCommand<TaskItemViewModel>
            ((task) => GetAllTasksAsync(task));

该命令调用的方法:

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

如果我没记错,GetAllTasksAsync被UI线程调用,但是当到达GetAllAsync().ConfigureAwait(false)时它退出上下文,然后GetAllAsync在线程池上下文中运行并在完成后返回UI线程并更新视图属性。

这种方法正确吗?

1 个答案:

答案 0 :(得分:4)

  

这种方法正确吗?

捕获异常并假装什么都没有发生,这不是最佳做法:

catch (Exception)
{
    return Enumerable.Empty<TaskItem>();
}

如果GetAllAsync()无法以有意义的方式处理异常,则最好避免捕获任何异常,并由调用方处理。或者,您可能想记录一个错误,然后重新引发异常:

public async Task<IEnumerable<TaskItem>> GetAllAsync()
{
    using (var context = new NotesContext())
    {
        try
        {
            return await context
                .Tasks
                .ToListAsync();
        }
        catch (Exception ex)
        {
            //log ex...
            throw;
        }
    }
}

此外,不返回诸如GetAllTasksAsync之类的值的异步方法应返回Task而不是void

public async Task GetAllTasksAsync(TaskListItemViewModel taskList){ ... }

否则,当您致电时,您将无法等待。

您关于捕获SynchronizationContextConfigureAwait的假设是正确的。