我有以下下载网页的功能:
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()
这是什么,我怎么抓住它?
发布于 2019-09-21 10:05:35
这个应用程序崩溃了,因为try/catch不是“到处抓它”的黑客,它只捕获在同一个调用堆栈上抛出的异常或相同的调用上下文。
另一方面,由于某种原因,您使用同步方法启动异步任务,这些任务在其他线程上运行,它们的上下文将丢失。
要么使用这些方法的同步版本,要么在异步任务上使用异步方法和await
,这将保留调用上下文,并允许您捕获try/catch块内部抛出的任何异常。
发布于 2019-09-21 10:16:19
请注意,这里描述的是一种旧的行为(如注释中所述),并且它不会发生在.NET 4.5和更新版本中。
正在发生的情况是,任务没有成功完成,您也没有检查错误。当垃圾收集器试图清理Task
对象时,它会在那里找到未处理的异常并将其抛入AggregateException
中。这就是异常并没有实际抛出在try
块中(甚至在不同的线程上),因此捕获无法捕获它。
您想要做的是正确地await
创建的任务。此时,您可能希望在C#中阅读异步/等待。如果您希望任务是可取消的,您可能必须使用GetAsync
和取消令牌,否则您将不得不等待GetStringAsync
在某个时候完成。
如果您出于某种原因不想使用异步等待方式(您应该这样做!),您仍然可以使用tsk.Wait();
。但是,这将将抛出的异常包装在AggregateException
中,调用将是同步的。
如果您真的不能停留在周围等待您的函数完成,您可以在this question中看到如何使用延续任务自动处理异常检查。
但是,我确实建议您使用异步/等待,并适当地检查任务是如何完成的,以及它们抛出了什么。
https://stackoverflow.com/questions/58039183
复制相似问题