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