【问题标题】:Try catch async await https exception尝试捕获异步等待 https 异常
【发布时间】:2014-12-01 00:30:54
【问题描述】:

我有一个看起来很奇怪的情况。我有一些异步/等待代码,它使用 RestSharp 从几种目录服务返回的几个休息 API(托管在不同 URL 上的相同 API)获取一些数据。

现在的问题是:所述目录服务返回的 API 之一在某种程度上是“私有的”,并且启动与其的 SSL 连接失败。 Fiddler 捕获以下响应:

HTTP/1.1 200 Connection Established
FiddlerGateway: Direct
StartTime: 19:13:11.117
Connection: close

fiddler.network.https> HTTPS handshake to foo.bar.com failed. System.IO.IOException The handshake failed due to an unexpected packet format.

如果发生这种情况,我最好跳过从该 API 获取数据并继续前进。然而,事实证明 try/catch 没有帮助!抛出 NullReferenceException,但即使是通用的 try/catch 也无法捕获它。

代码非常简单:

try
{
   await GetDataAsync(url);
}
catch 
{
   // never gets called
}

private async Task<List<Data>> GetDataAsync(string url)
{
   var request = new RestRequest("/foo");
   var restClient = new RestClient(url);

   var response = await restClient.ExecuteTaskAsync<List<Data>>(request); // <-- this throws 
   return response.Data;
}

我已将代码提取到库中,并在控制台应用程序和 WPF 应用程序中进行了尝试,结果相同,永远不会输入 catch 块。

有什么想法吗?

l.e.:根据要求,这是完整的异常堆栈跟踪

Unhandled Exception: System.NullReferenceException: Object reference not set to
an instance of an object.
at RestSharp.RestClient.<>c__DisplayClass15`1.<ExecuteTaskAsync>b__12(IRestResponse`1 response, RestRequestAsyncHandle _)
at RestSharp.RestClient.DeserializeResponse[T](IRestRequest request, Action`2 callback, IRestResponse response, RestRequestAsyncHandle asyncHandle)
at RestSharp.RestClient.<>c__DisplayClassa`1.<ExecuteAsync>b__9(IRestResponse response, RestRequestAsyncHandle asyncHandle)
at RestSharp.RestClient.ProcessResponse(IRestRequest request, HttpResponse httpResponse, RestRequestAsyncHandle asyncHandle, Action`2 callback)
at RestSharp.RestClient.<>c__DisplayClass3.<ExecuteAsync>b__0(HttpResponse r)
at RestSharp.Http.ExecuteCallback(HttpResponse response, Action`1 callback)
at RestSharp.Http.ResponseCallback(IAsyncResult result, Action`1 callback)
at RestSharp.Http.<>c__DisplayClass3.<GetStyleMethodInternalAsync>b__1(IAsyncResult result)
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.ContextAwareResult.CompleteCallback(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.ContextAwareResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.HttpWebRequest.SetResponse(Exception E)
at System.Net.HttpWebRequest.CheckWriteSideResponseProcessing()
at System.Net.ConnectStream.ProcessWriteCallDone(ConnectionReturnResult returnResult)
at System.Net.HttpWebRequest.WriteCallDone(ConnectStream stream, ConnectionReturnResult returnResult)
at System.Net.ConnectStream.CallDone(ConnectionReturnResult returnResult)
at System.Net.ConnectStream.IOError(Exception exception, Boolean willThrow)
at System.Net.ConnectStream.HandleWriteHeadersException(Exception e, WebExceptionStatus error)
at System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar)
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.TlsStream.ResumeIOWorker(Object result)
at System.Net.TlsStream.WakeupPendingIO(IAsyncResult ar)
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.Security.SslState.FinishHandshake(Exception e, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
at System.Net.AsyncProtocolRequest.CompleteRequest(Int32 result)
at System.Net.FixedSizeReader.CheckCompletionBeforeNextRead(Int32 bytes)
at System.Net.FixedSizeReader.ReadCallback(IAsyncResult transportResult)
at System.Net.LazyAsyncResult.Complete(IntPtr userToken)
at System.Net.ContextAwareResult.CompleteCallback(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.ContextAwareResult.Complete(IntPtr userToken)
at System.Net.LazyAsyncResult.ProtectedInvokeCallback(Object result, IntPtr userToken)
at System.Net.Sockets.BaseOverlappedAsyncResult.CompletionPortCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)

【问题讨论】:

  • return response.Data;下下断点,查看response的内容。
  • 我没有到达那条线,它会抛出 ExecuteTaskAsync。我编辑了问题以显示抛出的行。
  • 你能添加异常的堆栈跟踪吗?
  • 完成,编辑原帖
  • 如果异常没有被 try-catch 捕获,它在哪里被捕获?

标签: c# .net exception-handling async-await restsharp


【解决方案1】:

这似乎是a bug in RestSharp。我不确定您是否可以在不修改 RestSharp 的源代码的情况下做任何事情。

【讨论】:

  • 你是对的。我还发现github.com/restsharp/RestSharp/issues/447 基本上是相同的问题。但是,在从 GitHub 获取最新的 RestSharp 代码以了解异常导致 AppDomain 崩溃的原因后,我发现它现在已修复!我单步执行了反序列化代码,现在它可以正确检查是否存在异常并且不再尝试反序列化响应正文。
  • 我现在检查了一个较旧的 RestSharp 提交,其中错误仍然存​​在,以试图找出异常导致应用程序崩溃的原因。不太确定,但据我所知,RestSharp 中的异步方法似乎在 WebRequest 上包装了非异步方法(例如 BeginWebRequest)。我猜编译器重写异步/等待代码不支持在这种情况下引发的异常? (为了清楚起见,RestSharp4 的当前版本也是针对 .net4 编译的,并且仍然不使用 GetResponseAsync(),但由于实际错误已修复,因此不再抛出 NRE)
猜你喜欢
  • 1970-01-01
  • 2019-10-20
  • 2020-08-06
  • 1970-01-01
  • 2019-10-24
  • 2017-05-17
  • 2018-04-20
  • 1970-01-01
  • 2019-02-25
相关资源
最近更新 更多