C# Task.IsCompleted未返回正确的任务状态

C# Task.IsCompleted未返回正确的任务状态,c#,winforms,async-await,C#,Winforms,Async Await,我试图在Form1\u FormClosing事件期间捕获长时间运行任务的状态 长时间运行的任务由使用HttpClient的异步/等待调用组成 当我启动正在运行的任务时,它在循环中运行,直到被取消。但是,当我在任务仍在运行的情况下关闭表单时,任务状态与预期不符,并显示状态RanToCompletion和IsCompleted==true 我已经使用方法RunLongRunningMethodTest 任务延迟(2000)工作正常,但等待任务。延迟(2000)复制相同的问题。由于GetAsync方

我试图在
Form1\u FormClosing
事件期间捕获长时间运行任务的状态

长时间运行的任务由使用HttpClient的异步/等待调用组成

当我启动正在运行的任务时,它在循环中运行,直到被取消。但是,当我在任务仍在运行的情况下关闭表单时,任务状态与预期不符,并显示状态
RanToCompletion
IsCompleted==true

我已经使用方法
RunLongRunningMethodTest

任务延迟(2000)工作正常,但等待任务。延迟(2000)复制相同的问题。由于GetAsync方法的缘故,
GetUrl
也必须是异步的,我不知道如何回避这个事实

如何修复下面的代码,以便Form1\u 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}";
            }
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用系统组件模型;
使用系统数据;
使用系统诊断;
使用系统图;
使用System.Linq;
Net系统;
使用System.Net.Http;
使用System.Net.Http.Header;
使用系统文本;
使用系统线程;
使用System.Threading.Tasks;
使用System.Windows.Forms;
命名空间WindowsFormsApp1
{
公共部分类Form1:Form
{
私有静态HttpClient客户端{get;set;}
私有任务任务{get;set;}
私有CancellationTokenSource cts{get;set;}
私有布尔按钮启动停止状态{get;set;}
公共表格1()
{
初始化组件();
}
专用异步void RunLongRunningMethodTest(CancellationToken CancellationToken)
{
尝试
{
while(true)
{
if(cancellationToken.IsCancellationRequested)
{
cancellationToken.ThrowIfCancellationRequested();
}
Debug.WriteLine(DateTime.Now);
Task.Delay(2000);//Task.IsCompleted=false-正常工作
//等待Task.Delay(2000);//Task.IsCompleted=true-不正确
}
}
捕获(操作取消异常)
{
//无需登录即可退出。操作已被用户取消。
}
捕获(例外情况除外)
{
//报告错误
}
}
专用异步void RunLongRunningMethod(CancellationToken CancellationToken)
{
尝试
{
while(true)
{
if(cancellationToken.IsCancellationRequested)
{
cancellationToken.ThrowIfCancellationRequested();
}
var success=等待获取URL(“https://www.bbc.co.uk/");
《睡眠》(2000年);
}
}
捕获(操作取消异常)
{
//无需登录即可退出。操作已被用户取消。
}
捕获(例外情况除外)
{
//报告错误
}
}
专用异步任务GetUrl(字符串url)
{
if(客户端==null)
{
client=new-HttpClientHandler(){UseDefaultCredentials=true,AutomaticDecompression=DecompressionMethods.Deflate | DecompressionMethods.GZip});
client.BaseAddress=新Uri(“https://www.bbc.co.uk/");
client.DefaultRequestHeaders.Add(“接受”,“*/*”);
client.DefaultRequestHeaders.AcceptEncoding.Add(新的StringWithQualityHeaderValue(“gzip”);
client.DefaultRequestHeaders.Add(“用户代理”、“Mozilla/5.0(Windows NT 10.0;…)Gecko/20100101 Firefox/62.0”);
client.DefaultRequestHeaders.Add(“主机”https://www.bbc.co.uk/");
client.DefaultRequestHeaders.Connection.Add(“保持活动”);
client.DefaultRequestHeaders.Add(“DNT”,“1”);
}
var response=wait client.GetAsync(url);
var contents=wait response.Content.ReadAsStringAsync();
返回true;
}
私有无效按钮启动停止\单击(对象发送者,事件参数e)
{
buttonStartStopState=!buttonStartStopState;
如果(按钮启动停止状态)
{
cts=新的CancellationTokenSource();
任务=新任务(()=>RunLongRunningMethod(cts.Token));
task.Start();
}
其他的
{
cts.Cancel();
cts=null;
}
}
私有作废Form1\u FormClosing(对象发送方,FormClosingEventArgs e)
{
如果(任务!=null)
{
var taskStatus=$“{task.Status}{task.IsCompleted}”;
}
}
}
}

第一个问题是在长时间运行的方法中使用了
异步void
。当代码到达
await
行时,控件将退回父级,并且由于任务没有任何其他要运行的内容,因此它会正确地报告它已完成

那么,让我们来解决这个问题:

private async Task RunLongRunningMethodTest
private async Task RunLongRunningMethod
第二个问题是
任务
构造函数的使用。不仅不鼓励使用它,而且在代码中也不需要它。你应该这样做:

if (buttonStartStopState)
{
    cts = new CancellationTokenSource();
    task = RunLongRunningMethod(cts.Token); // will only compile after fixing the first problem
}

另外,请注意使用
Task.Delay(2000)实际上是无用的,因为您正在创建一个被丢弃的任务。

第一个问题是在长时间运行的方法中使用了
异步void
。当代码到达
await
行时,控件将返回给父级,因为任务没有任何内容