我具有以下下载网页的功能:
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()
这是什么,我该如何捕捉?
答案 0 :(得分:0)
该应用程序崩溃了,因为try / catch并非“随处捕获”黑客,它仅捕获在同一调用堆栈或同一调用上下文中引发的异常。
另一方面,由于某种原因,您使用同步方法来启动异步任务,这些任务在其他线程上运行,并且它们的上下文丢失。
或者使用这些方法的同步版本,或者更好的是,在异步任务上使用async方法和await
,这将保留调用上下文并允许您捕获try /中从内部抛出的任何异常。捕获块。
答案 1 :(得分:0)
请注意,此处描述的是旧行为(如注释中所述),. NET 4.5及更高版本不会发生。
正在发生的情况是任务未成功完成,并且您没有检查错误。当垃圾收集器尝试清理Task
对象时,它会在该对象中找到未处理的异常并将其扔到AggregateException
中。这是一个例外,实际上并没有引发您的try
块(它甚至在不同的线程上),因此您的catch无法捕获它。
您要执行的操作是正确await
创建的任务。此时,您可能想在C#中阅读异步/等待。如果您希望任务可以取消,则可能必须将GetAsync
与取消令牌一起使用,否则您将不得不等待GetStringAsync
在某个时候完成。
如果由于某种原因(您应该!)不希望使用异步等待方式,则仍然可以使用tsk.Wait();
。但是,这会将引发的异常包装在AggregateException
中,并且调用将是同步的。
如果您真的无法等待任务完成,则可以在this question中看到如何通过连续任务自动处理异常检查。
但是我真的建议您使用异步/等待并适当地检查任务如何完成以及它们抛出了什么。