【发布时间】:2018-12-25 11:31:41
【问题描述】:
我正在尝试在Form1_FormClosing 事件期间捕获长时间运行的任务的状态。
长时间运行的任务包括使用 HttpClient 的 async/await 调用。
当我开始运行任务时,它会循环运行直到被取消。但是,当我关闭表单且任务仍在运行时,任务状态与预期不符,并显示状态 RanToCompletion 和 IsCompleted==true
我已经使用方法RunLongRunningMethodTest复制了这个问题
Task.Delay(2000); 工作正常,但 await Task.Delay(2000); 复制了同样的问题。由于 GetAsync 方法,我不确定如何解决 GetUrl 也必须是异步的这一事实。
如何修复下面的代码,以便 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}";
}
}
}
}
【问题讨论】:
-
您根本不应该使用
Task构造函数,更不用说环绕async void方法了。从长时间运行的方法中返回一个任务,等待它们的完成。只有您的事件处理程序应标记为async void。
标签: c# winforms async-await