c# - 异步函数未被调用

标签 c# json .net-4.5

请原谅我在下面看到的任何笨拙的错误,我正在学习我正在尝试使用的一些概念。

问题: 在调试我的应用程序时,我能够使用 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/

相关文章:

asp.net-mvc-4 - 添加对 System.IdentityModel.Tokens DLL 的引用

c# - 哪个控件用于快速文本输入(输入框)?

c# - DocumentCompleted 的 WPF 等价物是什么?

ruby-on-rails - 如何为 API 禁用 JSON 中的转义 HTML 实体,但为 View 启用它?

android - 使用 Retrofit 在 JSON 中上传多部分图像数据?

python - 使用键中的冒号解析 JSON

c# - 为什么当内部 "finally"抛出时外部 "catch"没有被执行?

c# - IE 添加 http header PRAGMA : no-cache

asp.net - .NET 4.5 Gridview 在 EditItemTemplate UpdateMethod 中使用 DropDownList

c# - 检测wlan是否关闭