我正在尝试捕获Form1_FormClosing
事件期间长期运行的任务的状态。
长期运行的任务包括使用HttpClient进行异步/等待调用。
当我开始运行任务时,它会循环运行直到被取消。但是,当我在任务仍在运行的情况下关闭表单时,任务状态与预期不符,并显示状态RanToCompletion
和IsCompleted==true
我已经使用方法RunLongRunningMethodTest
Task.Delay(2000);
可以,但是await Task.Delay(2000);
复制相同的问题。我不确定GetUrl
由于GetAsync方法也必须是异步的。
如何修复下面的代码,以便Form1_FormClosing正确报告任务在运行时关闭仍在运行?我想检查任务状态,如果仍在运行,请取消,然后等待取消完成。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private static HttpClient client { get; set; }
private Task task { get; set; }
private CancellationTokenSource cts { get; set; }
private bool buttonStartStopState { get; set; }
public Form1()
{
InitializeComponent();
}
private async void RunLongRunningMethodTest(CancellationToken cancellationToken)
{
try
{
while (true)
{
if (cancellationToken.IsCancellationRequested)
{
cancellationToken.ThrowIfCancellationRequested();
}
Debug.WriteLine(DateTime.Now);
Task.Delay(2000); // task.IsCompleted = false - Works okay
//await Task.Delay(2000); // task.IsCompleted = true - Not correct
}
}
catch (OperationCanceledException)
{
// Just exit without logging. Operation cancelled by user.
}
catch (Exception ex)
{
// Report Error
}
}
private async void RunLongRunningMethod(CancellationToken cancellationToken)
{
try
{
while (true)
{
if (cancellationToken.IsCancellationRequested)
{
cancellationToken.ThrowIfCancellationRequested();
}
var success = await GetUrl("https://www.bbc.co.uk/");
Thread.Sleep(2000);
}
}
catch (OperationCanceledException)
{
// Just exit without logging. Operation cancelled by user.
}
catch (Exception ex)
{
// Report Error
}
}
private async Task<bool> GetUrl(string url)
{
if (client == null)
{
client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true, AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip });
client.BaseAddress = new Uri("https://www.bbc.co.uk/");
client.DefaultRequestHeaders.Add("Accept", "*/*");
client.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; …) Gecko/20100101 Firefox/62.0");
client.DefaultRequestHeaders.Add("Host", "https://www.bbc.co.uk/");
client.DefaultRequestHeaders.Connection.Add("Keep-Alive");
client.DefaultRequestHeaders.Add("DNT", "1");
}
var response = await client.GetAsync(url);
var contents = await response.Content.ReadAsStringAsync();
return true;
}
private void buttonStartStop_Click(object sender, EventArgs e)
{
buttonStartStopState = !buttonStartStopState;
if(buttonStartStopState)
{
cts = new CancellationTokenSource();
task = new Task(() => RunLongRunningMethod(cts.Token));
task.Start();
}
else
{
cts.Cancel();
cts = null;
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (task != null)
{
var taskStatus = $"{task.Status} {task.IsCompleted}";
}
}
}
}
答案 0 :(得分:2)
第一个问题是您在长期运行的方法中使用async void
。当代码到达await
行时,该控件将交还给父级,并且由于“任务”没有其他要运行的内容,因此正确报告其已完成。>
所以,我们来解决这个问题:
private async Task RunLongRunningMethodTest
private async Task RunLongRunningMethod
第二个问题是使用Task
构造函数。不仅不鼓励使用它,而且在您的代码中也不必要。您应该这样做:
if (buttonStartStopState)
{
cts = new CancellationTokenSource();
task = RunLongRunningMethod(cts.Token); // will only compile after fixing the first problem
}
请注意,使用Task.Delay(2000);
实际上是无用的,因为创建的任务被丢弃了。