发布
社区首页 >问答首页 >如何捕获异步HttpClient调用中的所有异常?

如何捕获异步HttpClient调用中的所有异常?
EN

Stack Overflow用户
提问于 2019-09-21 09:57:28
回答 2查看 1.3K关注 0票数 0

我有以下下载网页的功能:

代码语言:javascript
代码运行次数:0
复制
    static bool myFunction(int nmsTimeout, out string strOutErrDesc)
    {
        //'nmsTimeout' = timeout in ms for connection
        //'strOutErrDesc' = receives error description as string
        bool bRes = false;
        strOutErrDesc = "";

        HttpClient httpClient = null;
        System.Threading.Tasks.Task<string> tsk = null;

        try
        {
            httpClient = new HttpClient();
            tsk = httpClient.GetStringAsync("https://website-to-connet.com");

            if (tsk.Wait(nmsTimeout))
            {
                if (tsk.Status == System.Threading.Tasks.TaskStatus.RanToCompletion)
                {
                    string strRes = tsk.Result;
                    strRes = strRes.Trim();

                    if (!string.IsNullOrWhiteSpace(strRes))
                    {
                        bRes = true;
                    }
                    else
                    {
                        //Empty result
                        strOutErrDesc = "Empty result";
                    }
                }
                else
                {
                    //Bad task completion
                    strOutErrDesc = "Bad completion result: " + tsk.Status.ToString();
                }
            }
            else
            {
                //Timed out
                strOutErrDesc = "Timeout expired: " + nmsTimeout + " ms.";
            }
        }
        catch (Exception ex)
        {
            //Error
            strOutErrDesc = "Exception: " + ex.Message;
            if (tsk != null)
            {
                strOutErrDesc += " -- ";
                int c = 1;
                foreach(var exc in tsk.Exception.InnerExceptions)
                {
                    strOutErrDesc += c.ToString() + ". " + exc.InnerException.Message;
                }
            }

            bRes = false;
        }

        return bRes;
    }

我认为我的try/catch构造足够捕获其中的所有异常。

直到我发现了以下异常和该应用程序崩溃的Windows错误消息:

未处理异常: System.AggregateException:通过等待任务或访问其异常属性没有观察到任务的异常。因此,未观察到的异常由终结器线程重新引发。-> System.Net.Http.HttpRequestException:响应状态代码并不表示成功: 503 (服务不可用)。

-内部异常堆栈跟踪结束

在System.Threading.Tasks.TaskExceptionHolder.Finalize()

这是什么,我怎么抓住它?

EN

回答 2

Stack Overflow用户

发布于 2019-09-21 10:05:35

这个应用程序崩溃了,因为try/catch不是“到处抓它”的黑客,它只捕获在同一个调用堆栈上抛出的异常或相同的调用上下文。

另一方面,由于某种原因,您使用同步方法启动异步任务,这些任务在其他线程上运行,它们的上下文将丢失。

要么使用这些方法的同步版本,要么在异步任务上使用异步方法和await,这将保留调用上下文,并允许您捕获try/catch块内部抛出的任何异常。

票数 0
EN

Stack Overflow用户

发布于 2019-09-21 10:16:19

请注意,这里描述的是一种旧的行为(如注释中所述),并且它不会发生在.NET 4.5和更新版本中。

正在发生的情况是,任务没有成功完成,您也没有检查错误。当垃圾收集器试图清理Task对象时,它会在那里找到未处理的异常并将其抛入AggregateException中。这就是异常并没有实际抛出在try块中(甚至在不同的线程上),因此捕获无法捕获它。

您想要做的是正确地await创建的任务。此时,您可能希望在C#中阅读异步/等待。如果您希望任务是可取消的,您可能必须使用GetAsync和取消令牌,否则您将不得不等待GetStringAsync在某个时候完成。

如果您出于某种原因不想使用异步等待方式(您应该这样做!),您仍然可以使用tsk.Wait();。但是,这将将抛出的异常包装在AggregateException中,调用将是同步的

如果您真的不能停留在周围等待您的函数完成,您可以在this question中看到如何使用延续任务自动处理异常检查。

但是,我确实建议您使用异步/等待,并适当地检查任务是如何完成的,以及它们抛出了什么。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58039183

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档