请原谅我在下面看到的任何笨拙的错误,我正在学习我正在尝试使用的一些概念。
问题:
在调试我的应用程序时,我能够使用 Task.Start()
调用 async
函数。我觉得应用程序在我所处的阶段处于工作状态,因此使用 CTRL + SHIFT + F9 删除了所有断点。
一旦我在没有断点的情况下运行该应用程序,它就会因未填充属性而失败。现在,当我尝试调试我在 async
函数中设置的任何断点时,处理大部分工作的时间更长。就像它被跳过了一样。谁能看出为什么 GetWowAuctionFileInfo
没有被调用的原因?
GetWowAuctionFileInfo
没有被调用,或者至少看起来没有被调用。
谢谢。
相关代码
调用函数
private void buttonTestJSFCHI_Click(object sender, RoutedEventArgs e)
{
JSON_Worker w = new JSON_Worker();
w.StartTask("FileInfo", "https://us.api.battle.net/wow/auction/data/medivh?locale=en_US&apikey=<guid>");
foreach (string res in w.ReturnedData)
{
textBoxResults.Text += res;
}
}
调用函数
public void StartTask(string TaskName, string optionalUri= "no_uri_passed")
{
if (TaskName == "FileInfo")
{
//Need to use a lamba expression to call a delegate with a parameter
if (!(optionalUri == "no_uri_passed"))
{
Task t = new Task(() => GetWowAuctionFileInfo(optionalUri));
t.Start();
//Func<string> function = new Func<string>(() => GetWowAuctionFileInfo(optionalUri));
//Task<string> tInfo = Task<string>.Factory.StartNew(() => GetWowAuctionFileInfo(optionalUri));
}
}
}
private async void GetWowAuctionFileInfo(string auctionInfoUri)
{
RealmJSFileCheck realmInfoObject;
List<string> returnValue = new List<string>();
try
{
using (HttpClient client = new HttpClient())
{
for (int attempt = 0; attempt < 3; attempt++)
{
var response = await client.GetAsync(auctionInfoUri);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
realmInfoObject = JsonConvert.DeserializeObject<RealmJSFileCheck>(content);
returnValue = ConvertFileInfoToConsumableList(realmInfoObject);
//returnValue = realmInfoObject.files.ToString();
break;
}
}
}
}
catch (InvalidOperationException iOpEx)
{
//recieved this when an invalid uri was passed in
}
ReturnedData = returnValue;
}
private List<string> ConvertFileInfoToConsumableList(RealmJSFileCheck jsfc)
{
List<string> returnData = new List<string>();
if (jsfc.files.Count > 0)
{
StringBuilder sb = new StringBuilder();
sb.Append("File URL: ");
sb.Append(jsfc.files[0].url);
returnData.Add(sb.ToString());
sb = new StringBuilder();
sb.AppendLine("Last Modified: ");
sb.Append(jsfc.files[0].lastModified);
returnData.Add(sb.ToString());
}
else
{
returnData.Add("No File Info Found");
}
return returnData;
}
更新 再次感谢大家的详细评论。我浏览了很多关于 Task 用法的文档,并在这个练习中学到了很多东西。我将 @Johnathon 的答案标记为解决方案,因为它提供了我所要求的内容,并提供了一个非常有用的链接以获取更多信息。
最佳答案
你的 GetWowAuctionFileInfo
方法是一种异步方法,您等待其中的异步调用而不返回任务。一般来说,使用 async void
是不好的做法。 .相反,把你的 GetWowAuctionFileInfo
方法进入async Task<List<string>> GetWowAuctionFileInfo
.这会让你等待 GetAsync
调用、解析数据并将集合返回给调用者,而无需使用 ReturnObject
.
private async Task<List<string>> GetWowAuctionFileInfo(string auctionInfoUri)
{
RealmJSFileCheck realmInfoObject;
List<string> returnValue = new List<string>();
try
{
using (HttpClient client = new HttpClient())
{
for (int attempt = 0; attempt < 3; attempt++)
{
var response = await client.GetAsync(auctionInfoUri);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
realmInfoObject = JsonConvert.DeserializeObject<RealmJSFileCheck>(content);
// You can just return the List<T> now.
return ConvertFileInfoToConsumableList(realmInfoObject);
//returnValue = realmInfoObject.files.ToString();
break;
}
}
}
}
catch (InvalidOperationException iOpEx)
{
//recieved this when an invalid uri was passed in
}
}
因为方法原来是async void
, 你不能等待在你的 buttonTestJSFCHI_Click
中调用它.现在我们已经使它全部基于任务,您可以在事件处理程序中等待它。请注意,事件处理程序通常是唯一可接受的使用位置 async void
.任何时候您负责方法的创建,并且不受契约(Contract)约束(如事件处理程序),您应该始终在异步方法上返回一个任务。
private async void buttonTestJSFCHI_Click(object sender, RoutedEventArgs e)
{
JSON_Worker w = new JSON_Worker();
List<string> results = await w.StartTask("FileInfo", "https://us.api.battle.net/wow/auction/data/medivh?locale=en_US&apikey=<guid>");
foreach (string res in results)
{
textBoxResults.Text += res;
}
}
public async Task<List<string>> StartTask(string TaskName, string optionalUri= "no_uri_passed")
{
if (TaskName == "FileInfo")
{
//Need to use a lamba expression to call a delegate with a parameter
if (!(optionalUri == "no_uri_passed"))
{
// Since the GetWowAuctionFileInfo now returns Task, we don't need to create a new one. Just await the Task given back to us, and return the given result.
return await GetWowAuctionFileInfo(optionalUri);
}
}
}
您在调试时看到预期结果的原因是调试 session 足够慢,以至于异步操作及时完成,您的代码可以使用它。在调试器外部运行应用程序时,它的运行速度比异步操作可以完成的速度快,从而阻止您查看数据。因此需要await
整个异步调用堆栈,因此您可以防止在该代码路径下进一步执行,直到您收到所有所需数据。
Microsoft has a good write up关于基于任务的编程,我会通读它以帮助您理解它。
编辑
澄清一下,当您返回 Task<T>
时在你的方法上,你会在等待时得到结果。例如:
List<string> result = await StartTask();
尽管StartTask
返回 Task<List<string>>
, await
操作将等待 StartTask()
方法完成,然后解包 Task<T>
的结果对象并自动返回结果。所以不要让方法签名欺骗你,如果你 await
它,您将返回结果数据,而不是实际的 Task
本身。您不需要从 Task
中提取数据手动。
关于c# - 异步函数未被调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40821768/