首页 > 解决方案 > 取消不可取消的任务

问题描述

我在代码库中有以下代码:

public async Task<HttpApiResponse> FindUsers(Guid userId)
{
    try
    {
        AccessToken token = tokenService.GetAccessToken();
        channel = channelFactory.CreateChannelWithToken(token);
        HttpApiResponse response = await channel.FindUsers(request);

        return response.ToDto();
    }
}

现在我喜欢在这里使用 CancellationToken,但我不太确定我是否做得对:

public async Task<HttpApiResponse> FindUsers(Guid userId, CancellationToken ct)
{
    try
    {
        var taskCompletionSource = new TaskCompletionSource<decimal>();

        ct.Register(() =>
        {
            // We received a cancellation message, cancel the TaskCompletionSource.Task
            taskCompletionSource.TrySetCanceled();
        });

        AccessToken token = await tokenService.GetAccessToken();
        
        await Task.WhenAny(token, taskCompletionSource.Task).ContinueWith(async token => 
        {
            channel = channelFactory.CreateChannelWithToken(token);
            HttpApiResponse response = await channel.FindUsers(request);

            return response.ToDto();
        });   
    }
}

我不确定的原因是因为我不确定我应该如何处理await channel.FindUsers(request);内部ContinueWith。我是否需要处理它,因为我在获取令牌时已经处理它?

标签: c#asp.net-core

解决方案


您不能真正取消不支持取消的 API,但您可以在调用之前使用TaskCompletionSource从您的方法返回并完成,如果这是您想要的。FindUsersGetAccessTokenFindUsers

OperationCanceledException如果CancellationToken在当前实现/重载FindUsers返回值之前取消,则以下重载将抛出一个:

public async Task<HttpApiResponse> FindUsers(Guid userId, CancellationToken ct)
{
    var taskCompletionSource = new TaskCompletionSource<decimal>();
    using (ct.Register(() => taskCompletionSource.TrySetCanceled()))
    {
        var findUsersTask = FindUsers(userId);
        await Task.WhenAny(findUsersTask, taskCompletionSource.Task);
        ct.ThrowIfCancellationRequested();
        return findUsersTask.Result;
    }
}

推荐阅读