我正在尝试在我的应用程序中学习和实现 async/await 关键字。我正在使用 API 获取数据,然后将它们显示在我的表单上。当我尝试从控制台应用程序调用方法时没有问题。但是,如果我从 Form_Shown 事件调用我的异步方法,也没有异常,但方法不起作用。
所以我在 Form_Shown 事件上调用我的 RefreshOrLoadDataToCache() 方法。
private async void LogTimeReport_Shown(object sender, EventArgs e)
{
// Some syncronous operations
RefreshOrLoadDataToCache(); // Async methods in it
// Some syncronous operations
}
在我的这个方法中创建了一个任务并等待它。
private async void RefreshOrLoadDataToCache()
{
if (IsNeededToCallAPI())
{
var taskForTimeEntries = LoadTimeEntriesTemp();
Task.WhenAll(taskForTimeEntries);
DataTable dtTimeEntriesTemp = taskForTimeEntries.Result;
DataTable dtEventsTemp = LoadEventsTemp();
dtTimeEntriesTemp.Merge(dtEventsTemp);
}
else
BindGridViews();
}
这是我的异步方法。
private async Task<DataTable> LoadTimeEntriesTemp()
{
TimeEntryHandler timeHandler = new TimeEntryHandler();
TimeEntryResponse response = await timeHandler.GetTimeEntries();
DataTable dt = DatatableHelper.ToDataTable<TimeEntry>(response.TimeEntries);
foreach (DataRow drow in dt.Rows)
{
// Some operations on DataTable
}
return dt;
}
在这种方法中,我连接到 API 并获得结果。我认为我的问题是关于这种方法。因为当我从控制台应用程序调用此方法时,它会返回数据。但是从表单申请它等待很长时间但没有结果或异常。
private async Task<TimeEntryResponse> GetTimeEntries()
{
using (var client = new AuthorizedHttpClient(_client))
{
var data = await client.GetAsync<TimeEntryResponse>(parameters);
if (data.StatusCode == HttpStatusCode.OK)
{
var response = (TimeEntryResponse)data.ContentObj;
response.Pages = int.Parse(data.Headers.GetValues("X-Pages").First());
response.Page = int.Parse(data.Headers.GetValues("X-Page").First());
response.TotalRecords = int.Parse(data.Headers.GetValues("X-Records").First());
return response;
}
return new TimeEntryResponse() { TimeEntries = null, STATUS = "ERROR" };
}
}
我认为 Windows 窗体上的异步调用缺少一些东西。如何修复我的代码?
最佳答案
你的代码有几个问题
您将一个方法标记为
async
,但您不等待其中的操作。您目前这样做是因为RefreshOrLoad
是async void
。它实际上需要是async Task
,其中底层返回的任务是正在进行的异步操作。然后,返回的Task
应该等待:private async void LogTimeReport_Shown(object sender, EventArgs e) { // Some syncronous operations await RefreshOrLoadDataToCache(); // Async methods in it // Some syncronous operations }
RefreshOrLoad
是一种异步方法。您使用Task.WhenAll
,它用于异步等待多个任务,但您也不需要await
。然后,您调用.Result
,which causes your code to effectively deadlock .所需要做的就是等待任务从LoadTimeEntriesTemp
返回:private async Task RefreshOrLoadDataToCache() { if (IsNeededToCallAPI()) { DataTable dtTimeEntriesTemp = await LoadTimeEntriesTemp(); DataTable dtEventsTemp = LoadEventsTemp(); dtTimeEntriesTemp.Merge(dtEventsTemp); } else BindGridViews(); }
我还注意到您应该将
*Async
后缀与您的异步方法一起使用。
修复这些问题时,您会发现代码的行为符合预期,一直是异步的。
关于c# - 异步/等待 Windows 窗体应用程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31892043/