提问人:nilsakesson 提问时间:8/11/2023 最后编辑:nilsakesson 更新时间:8/11/2023 访问量:393
使用 HttpClient 和 C 语言中的超时进行完全异常处理#
Full exception handling with HttpClient and timeouts in C#
问:
我正在尝试构建一个 wpf 应用程序,该应用程序将充当某些设备的子网扫描程序。一些 IP 地址将回复响应,而其他 IP 地址将由于没有收到请求而超时。我正在使用 Task.WhenAll() 异步执行所有请求,当达到 HttpClient.Timeout 时,任务将按预期取消,并且 UI 仍具有响应性。一段时间后,UI 冻结,HttpRequestExceptions 和 SocketExceptions 从已取消的线程中出现。我确实尝试使用取消令牌,但行为相同。 是否可以取消来自 HttpClient 的完整请求,或者是否可以更好地处理异常以使 UI 不冻结?
这是带有一个 url 示例的代码,该 url 可以正常工作,并且不会回复和超时。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows;
namespace TestWPF
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public async Task<string> GetStatus(string url)
{
using HttpClient client = new HttpClient();
client.Timeout = TimeSpan.FromSeconds(2);
try
{
var HTTPResponse = await client.GetStreamAsync(url);
string response = new System.IO.StreamReader(HTTPResponse).ReadToEnd();
return response;
}
catch (Exception e)
{
throw;
}
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
List<Task> tasks = new List<Task>
{
GetStatus("https://api.thecatapi.com/v1/images/search"),
GetStatus("https://192.168.0.31")
};
try
{
await Task.WhenAll(tasks);
}
catch (Exception ex)
{
Debug.WriteLine($"Exception: {ex}");
}
// Loop results
var successfulTasks = tasks.Where(task => task.Status == TaskStatus.RanToCompletion);
// Process the results of successful tasks
foreach (var successfulTask in successfulTasks)
{
// Get the return value inside the task
string scanResult = ((Task<string>)successfulTask).Result;
Debug.WriteLine(scanResult);
}
}
}
}
以及随之而来的例外。可以看出,HttpRequestException 和 SocketException 是在取消任务之后出现的。
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Private.CoreLib.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Private.CoreLib.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Private.CoreLib.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Private.CoreLib.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Private.CoreLib.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Net.Http.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Private.CoreLib.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in TestWPF.dll
Exception thrown: 'System.Threading.Tasks.TaskCanceledException' in System.Private.CoreLib.dll
Exception: System.Threading.Tasks.TaskCanceledException: The request was canceled due to the configured HttpClient.Timeout of 2 seconds elapsing.
---> System.TimeoutException: A task was canceled.
---> System.Threading.Tasks.TaskCanceledException: A task was canceled.
at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.GetStreamAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
--- End of inner exception stack trace ---
at System.Net.Http.HttpClient.HandleFailure(Exception e, Boolean telemetryStarted, HttpResponseMessage response, CancellationTokenSource cts, CancellationToken cancellationToken, CancellationTokenSource pendingRequestsCts)
at System.Net.Http.HttpClient.GetStreamAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
at TestWPF.MainWindow.GetStatus(String url)
at TestWPF.MainWindow.Button_Click(Object sender, RoutedEventArgs e)
[{"id":"9l6","url":"https://cdn2.thecatapi.com/images/9l6.jpg","width":720,"height":960}]
The thread 0x3a0c has exited with code 0 (0x0).
Exception thrown: 'System.Net.Sockets.SocketException' in System.Net.Sockets.dll
Exception thrown: 'System.Net.Sockets.SocketException' in System.Private.CoreLib.dll
Exception thrown: 'System.Net.Http.HttpRequestException' in System.Net.Http.dll
Exception thrown: 'System.Net.Http.HttpRequestException' in System.Private.CoreLib.dll
Exception thrown: 'System.Net.Http.HttpRequestException' in System.Private.CoreLib.dll
Exception thrown: 'System.Net.Http.HttpRequestException' in System.Private.CoreLib.dll
答:
0赞
Charlieface
8/11/2023
#1
你陷入了僵局。您需要使用 .您还应该处理这些对象。ReadToEnd
await ReadToEndAsync
此外,如果发生 DNS 故障,有时直到 15 秒才超时。因此,请改用 a。client.Timeout
CancellationToken
此外,您应该使用单个 ,以避免套接字耗尽。HttpClient
static HttpClient _client = new HttpClient() { Timeout = TimeSpan.FromSeconds(2) };
public async Task<string> GetStatus(string url)
{
using var cts = new cancellationTokeSource(2000);
using var HTTPResponse = await _client.GetStreamAsync(url, cts.Token);
using var sr = new StreamReader(HTTPResponse);
string response = await sr.ReadToEndAsync(cts.Token);
return response;
}
评论
0赞
nilsakesson
8/11/2023
即使进行了所有这些更改,TaskCanceledException 也是正在处理的更改,并且 HttpRequestException 和 SocketException 正在冻结 UI 线程。cancelationToken 不会取消请求,因此即使它是 DNS 问题,它似乎也无法解决它。
上一个:异常处理的奇怪行为
下一个:如何控制异常弹出行为?
评论