我编写了一个静态类来测试用户的互联网连接,并在连接状态发生变化时引发事件:
class InternetConnectionMonitor
{
public static EventHandler<EventArgs<bool>> StatusChanged;
private static bool isCancelled;
private static bool isConnected;
private static bool IsConnected
{
get
{
return isConnected;
}
set
{
if (isConnected != value)
{
StatusChanged(null, new EventArgs<bool>(value));
}
isConnected = value;
}
}
public static async void Start(TimeSpan interval)
{
//TODO Use a 1st party webpage for connectivity testing.
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromSeconds(2);
while (!isCancelled)
{
try
{
await client.GetAsync("http://example.com");
IsConnected = true;
}
catch (Exception)
{
IsConnected = false;
}
await Task.Delay(interval);
}
}
}
public static void Stop()
{
isCancelled = true;
}
}
这个类非常有效,但是,在我的应用程序中使用TPL Dataflow进行其他一些处理时,在Start()方法的while循环中引发异常,说任务被取消了。我在这里发帖的原因是因为我从不取消任何任务。
这是我正在进行的处理。在QueueTests完成后,InternetConnectionMonitor中会引发任务取消异常,尽管QueueTests不会引用任何InternetConnectionMonitor。
如果我不调用validateProxies(),则永远不会引发异常。
private async void validateProxies(IEnumerable<Proxy> proxies)
{
validateProxiesButton.Enabled = false;
cancelValidatingProxiesButton.Enabled = true;
addProxiesButton.Enabled = false;
removeProxiesButton.Enabled = false;
proxyTester = new ProxyTester();
await proxyTester.QueueTests(proxies, judges);
validateProxiesButton.Enabled = true;
cancelValidatingProxiesButton.Enabled = false;
addProxiesButton.Enabled = true;
removeProxiesButton.Enabled = true;
MessageBox.Show("Complete!");
}
public class ProxyTester
{
private PauseOrCancelTokenSource pcts = new PauseOrCancelTokenSource();
public async Task QueueTests(IEnumerable<Proxy> proxies, IEnumerable<ProxyJudge> judges, int maxConcurrency = 100)
{
var testProxies = new ActionBlock<(Proxy proxy, IProxyTest test)>((tup) =>
{
tup.proxy.Status = ProxyStatus.Testing;
tup.proxy.Status = tup.proxy.TestValidity(tup.test);
}, new ExecutionDataflowBlockOptions { CancellationToken = pcts.Token.CancellationToken, MaxDegreeOfParallelism = maxConcurrency });
//Set each proxies status to Queued, and post to the dataflow block.
foreach (var proxy in proxies)
{
proxy.Status = ProxyStatus.Queued;
await testProxies.SendAsync((proxy, judges.GetRandomItem()));
}
testProxies.Complete();
try
{
await testProxies.Completion;
}
catch (Exception)
{
}
}
public void Cancel()
{
pcts.Cancel();
}
}
启动InternetConnectionMonitor(由JleruOHeP在评论中请求)
public proxyTesterView()
{
InitializeComponent();
InternetConnectionMonitor.StatusChanged += InternetConnectionMonitor_StatusChanged;
InternetConnectionMonitor.Start(TimeSpan.FromSeconds(1));
}
private void InternetConnectionMonitor_StatusChanged(object sender, EventArgs<bool> e)
{
if (e.Value == true)
{
MessageBox.Show("Online");
}
else
{
MessageBox.Show("Offline");
}
}
答案 0 :(得分:1)
解决了我自己的问题并希望分享我的解决方案。经过一番思考之后,我感觉线程池线程在调用QueueTests时可能会变得筋疲力尽,因为默认的最大并行度(100)很高。这个线程池耗尽似乎对客户端的调用产生了意想不到的副作用。在InternetConnectionMonitor的Start()方法中出现了GetAsync,导致请求超时不正确地触发,从而导致TaskCancelledException。
所以我产生了我自己的显式线程,并在其中同步执行测试。例外情况已经消失并且正在按预期工作。
public static void Start()
{
//TODO Use a 1st party webpage for connectivity testing.
var t = new Thread(() =>
{
while (!isCancelled)
{
try
{
var req = HttpWebRequest.Create("http://example.com");
req.Timeout = 1000;
using (var resp = req.GetResponse())
{
resp.Close();
}
IsConnected = true;
}
catch (Exception ex)
{
IsConnected = false;
}
Console.WriteLine(IsConnected);
Thread.Sleep(1000);
}
});
t.Start();
}