C# 如何在.NET中Task.Wait()之后取消正在运行的OpenAsync()?

C# 如何在.NET中Task.Wait()之后取消正在运行的OpenAsync()?,c#,.net,task,kill,cancellationtokensource,C#,.net,Task,Kill,Cancellationtokensource,我想通过anytime Client click按钮连接到DB。当客户端使用不同的ConnectionString多次单击按钮时。现在我只想返回客户端创建的最后一个连接。因此,我必须取消上一个任务并创建新任务。问题是调用Task.wait()后如何取消任务?使用CancellationToken?因为当我还没有调用wait()时,任务状态将是WaitForActive,所以我将永远无法收到结果。请帮我解决那个案子。我的代码草案如下: private SqlConnection _conn

我想通过anytime Client click按钮连接到DB。当客户端使用不同的ConnectionString多次单击按钮时。现在我只想返回客户端创建的最后一个连接。因此,我必须取消上一个任务并创建新任务。问题是调用Task.wait()后如何取消任务?使用CancellationToken?因为当我还没有调用
wait()
时,任务状态将是WaitForActive,所以我将永远无法收到结果。请帮我解决那个案子。我的代码草案如下:

    private SqlConnection _connection = null;
    private CancellationTokenSource _source = null;
    private Task<string> _result = null;
    
    public Task<string> GetStatusAsync(string connectionString)
    {
        if (_source == null)
            _source = new CancellationTokenSource();
        if (_connection != null && _connection.State == ConnectionState.Connecting)
        {
            _source.Cancel();
            _source = new CancellationTokenSource();
        }

        _result = ConnectDatabaseAsync(connectionString.Trim(),_source.Token);
        _result.Wait();
        return _result;
    }

    private async Task<string> ConnectDatabaseAsync(string connectionString, CancellationToken cancellationToken)
    {                        
        if (_connection == null)
            _connection = new SqlConnection();
        try
        {
            _connection.ConnectionString = connectionString;
            await _connection.OpenAsync(cancellationToken);
            return "ok";
        }
        catch (Exception ex)
        {
            return ex.Message;
        }
        finally
        {
            if (_connection.State == ConnectionState.Open)
                _connection.Close();
        }
    }
private SqlConnection\u connection=null;
private CancellationTokenSource _source=null;
私有任务_result=null;
公共任务GetStatusAsync(字符串连接字符串)
{
如果(_source==null)
_source=新的CancellationTokenSource();
if(_connection!=null&&u connection.State==ConnectionState.Connecting)
{
_source.Cancel();
_source=新的CancellationTokenSource();
}
_结果=ConnectDatabaseAsync(connectionString.Trim(),_source.Token);
_result.Wait();
返回结果;
}
专用异步任务ConnectDatabaseAsync(字符串连接字符串,CancellationToken CancellationToken)
{                        
if(_connection==null)
_connection=newsqlconnection();
尝试
{
_connection.ConnectionString=ConnectionString;
wait\u connection.OpenAsync(cancellationToken);
返回“ok”;
}
捕获(例外情况除外)
{
返回ex.消息;
}
最后
{
if(_connection.State==ConnectionState.Open)
_connection.Close();
}
}

由于冻结主线程,所以不要使用等待任务

您可以使用任务和取消令牌的字典来像这样管理您的任务(我只是模拟您的方法):

private static readonly Dictionary Tasks=new Dictionary();
公共异步任务GetStatusAsync()
{
var source=新的CancellationTokenSource();
var task=ConnectDatabaseAsync(“YourConnection”,source.Token);
if(Tasks.Any())
foreach(任务中的变量项)
{
如果(!item.Key.IsCompleted&!item.Value.IsCancellationRequested)
item.Value.Cancel();
}
任务。添加(任务、源);
等待任务;
返回任务。结果;
}
专用异步任务ConnectDatabaseAsync(字符串连接、CancellationToken令牌)
{
等待任务。延迟(10000,令牌);
返回“Ok”;
}

您不应该使用
\u result.Wait()
-这会阻止线程,因此用户将永远无法单击该按钮-您的整个应用程序将被禁用frozen@torvin谢谢我知道。Wait任务将使用相同的Wait(),因为调用Wait或Wait()后,我的任务将永远不会启动。您使用WinForm或web app?@Saeed WinForm。你知道吗?我可以看出你有一个条件是
!item.Key.IsCompleted&!item.Value.IsCancellationRequested
并调用
cancel()
方法进行取消。那么,cancel()方法bro在哪里?如果!item.Value.IsCancellationRequested为true,可能我不想终止最后一个任务。@Steventrin使用fire取消令牌可以结束任务。当您从
CancellationTokenSource
调用
Cancel
方法时,您将取消该任务,并且不需要额外的Cancel方法。对于该
If
when
item.Key.IsCompleted
为true表示任务已完成且无法取消,when
item.Value.IsCancellationRequested
为true表示任务已取消且无需取消。@Steventrin您测试过这个答案吗?可以吗?已经检查过了。这里有个问题。这就是OpenAsync()运行的时间。它将首先检查CancellationToken,然后调用Open()方法进行连接。因此,稍后,我调用Cancel(),但它不会取消OpenAsync(),因为它已跳出check cancellationtoken部分。@StevenTrinh否如果在运行任务期间触发取消标记,它将取消该任务。我认为,你们的问题是在新的传入任务之前取消队列中的所有任务,这个解决方案就是这样做的。
      private static readonly Dictionary<Task, CancellationTokenSource> Tasks = new Dictionary<Task, CancellationTokenSource>();
      public async Task<string> GetStatusAsync()
        {
            var source = new CancellationTokenSource();
            var task = ConnectDatabaseAsync("YourConnection", source.Token);

            if (Tasks.Any())
                foreach (var item in Tasks)
                {
                    if (!item.Key.IsCompleted && !item.Value.IsCancellationRequested)
                        item.Value.Cancel();
                }

            Tasks.Add(task, source);

            await task;

            return task.Result;
        }

        private async Task<string> ConnectDatabaseAsync(string connection, CancellationToken token)
        {
            await Task.Delay(10000, token);

            return "Ok";
        }