我已经继承了一些代码,其中此模式(简化)用于每秒轮询设备,并检查它是否具有通过REST api的新数据:
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Threading.Tasks;
using System.Net.Http;
public class Class
{
private readonly string _iotIPaddress = "123.456.789.0";
private System.Timers.Timer _timer = null;
private readonly HttpClient _client = new HttpClient();
public Constructor()
{
_client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(--secrets--);
_client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
_timer = new System.Timers.Timer(TimeSpan.FromSeconds(1).TotalMilliseconds);
_timer.Elapsed += OnTimer;
}
private async void OnTimer(object sender, EventArgs e)
{
try
{
_timer.Stop();
var success = await ProcessUpdates();
// Some stuff depending on whether ProcessUpdates succeeded
}
catch (Exception ex)
{
// Log the exception
}
finally
{
_timer.Start();
}
}
private async Task<SomeSettingsStruct> ProcessUpdates()
{
try
{
string json = await _client.GetStringAsync($"http://{_iotIPaddress}/di_value/slot_0"); //Exception is thrown on this line
var resultdata = JsonConvert.DeserializeObject<SomeSettingsStruct>(json);
return resultdata;
}
catch (Exception e)
{
//Log the exception
return null;
}
}
}
在大多数情况下,这可以正常工作。但是有时连接会滞后(设备通过wifi连接到设备),GetStringAsync抛出一些预期的异常(呵呵),但有时这似乎会导致代码长时间阻塞。这可能表明网络问题持续了超过几分钟,但现场人员并不相信这种情况。因此,问题必须出在代码中。
尤其是这种异步回调方法并不适合我,计时器无论如何都会在不同线程上调用它的回调,那么回调中的异步/等待东西会发生什么?是在计时器线程上调用的,还是它们自己的任务? 这会导致竞争状况,用HttpClient做奇怪的事情吗?
这是我会在日志中看到的例外情况:
在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task任务)在System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务)在C.的Example.Namespace.Class.d__13.MoveNext() \ dev \ Project \ Example \ Namespace \ Class.cs:第103行
由于我们还记录了FirstChanceExceptions,因此我经常看到这种情况在发生之前:
发生异常:由于线程退出或应用程序请求123.456.789.0:80
,I/O操作已中止。
答案 0 :(得分:2)
因此,问题必须出在代码中。
不一定。我认为您的代码完全没有问题。
HttpClient
在发生超时时(即,没有响应并且放弃等待时)抛出TaskCanceledException
。这不是很直观,people have complained就是这样。
人们have found workarounds使它抛出更好的异常,但是我认为您不必为此烦恼。唯一一次抛出TaskCanceledException
的情况是,如果您通过了CancellationToken
,则表示已取消。但是您没有传递一个,因此可以确定如果它确实抛出了TaskCanceledException
,那是因为超时。
您可以将超时(_client.Timeout
)超时(Wireshark)超过默认的100秒,但是如果这是通过不可靠的无线连接进行的,则可能无济于事。
我的赌注是关于网络问题。您可以使用{{3}}进行验证(验证请求已发送,但未收到任何请求)。