我有一个Web API服务,用于检索和更新一组特定的数据(MyDataSet对象),在执行以下事件时,我在使用async / await时遇到了一些困惑:
在我的客户中,我有类似以下的内容:
Harmony.cs
private async Task<string> GetDataSet(string request)
{
using(var httpClient = new HttpClient())
{
httpClient.baseAddress = theBaseAddress;
HttpResponseMessage response = await httpClient.GetAsync(request);
response.EnsureSuccessStatusCode();
return response.Content.ReadAsStringAsync().Result;
}
}
private async Task PostDataSet<T>(string request, T data)
{
using (var httpClient = new HttpClient())
{
client.BaseAddress = new Uri(theBaseAddress);
HttpResponseMessage response = await client.PostAsJsonAsync<T>(request, data);
response.EnsureSuccessStatusCode();
}
}
internal MyDataSet GetMyDataSetById(int id)
{
string request = String.Format("api/MyDataSet/GetById/{0}", id);
return JsonConvert.DeserializeObject<MyDataSet>(GetDataSet(request).Result);
}
internal void UpdateDataSet(MyDataSet data)
{
PostDataSet("api/MyDataSet/Update", data);
}
HarmonyScheduler.cs
internal void ScheduleDataSet()
{
MyDataSet data = ...
harmony.UpdateDataSet(data);
MyDataSet data2 = harmony.GetMyDataSetById(data.Id);
}
Harmony.cs UpdateDataSet中存在编译器警告,因为没有等待调用,并且在调用完成之前将继续执行。这会影响程序执行,因为在更新发生之前正在检索data2。
如果我要使UpdateDataSet异步并添加等待它,那么它只是将堆栈中的内容移动到一个级别,现在HarmonyScheduler会收到关于不等待的警告。
如何在检索data2之前等待更新完成,以便在data2对象中获得更新的值?
答案 0 :(得分:2)
如何在检索data2之前等待更新完成, 这样我将在data2对象中获得更新的值?
我看到许多人不理解的事实是,使用带有async-await
的TAP会像瘟疫一样感染您的代码。
我的意思是什么? 使用TAP会导致异步一直冒泡到调用堆栈的顶部,这就是为什么他们说async方法“一直”。这是使用该模式的建议。通常,这意味着如果要引入异步API,则必须将其与单独的同步API一起提供。大多数人试图在两者之间进行混合和匹配,但这会导致whole lot of trouble(以及许多SO问题)。
为了让事情正确,您必须将UpdateDataSet
和GetMyDataSetById
变为异步。结果应如下所示:
private readonly HttpClient httpClient = new HttpClient();
private async Task<string> GetDataSetAsync(string request)
{
httpClient.BaseAddress = theBaseAddress;
HttpResponseMessage response = await httpClient.GetAsync(request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
private async Task PostDataSetAsync<T>(string request, T data)
{
client.BaseAddress = new Uri(theBaseAddress);
HttpResponseMessage response = await client.PostAsJsonAsync<T>(request, data);
response.EnsureSuccessStatusCode();
}
internal async Task<MyDataSet> GetMyDataSetByIdAsync(int id)
{
string request = String.Format("api/MyDataSet/GetById/{0}", id);
return JsonConvert.DeserializeObject<MyDataSet>(await GetDataSetAsync(request));
}
internal Task UpdateDataSetAsync(MyDataSet data)
{
return PostDataSetAsync("api/MyDataSet/Update", data);
}
注意 - HttpClient
是meant to be reused而不是一次性的单个调用对象。我将封装为类级别字段并重用它。
如果要公开同步API,请使用公开同步API的HTTP库(例如WebClient
)来执行此操作。
答案 1 :(得分:0)
在您需要结果之前,请务必等待任务。
如果任务在其正文中包含await
,那么等待任务总是更好。
警告:请勿使用.Wait()
或.Result
如果按照Control Flow in Async Programs所述进行控制流程,您会更好地理解这个概念。
因此,在您的情况下,我会使所有函数访问异步方法GetDataSet(string request)
和PostDataSet<T>(string request, T data)
,返回类型为Task
等待。
答案 2 :(得分:-1)
由于您似乎不期望从PostDataSet函数返回任何结果,您可以等待它完成。
PostDataSet("api/MyDataSet/Update", data).Wait();