如何取消任务C#

如何取消任务C#,c#,xamarin.forms,async-await,task-parallel-library,cancellation,C#,Xamarin.forms,Async Await,Task Parallel Library,Cancellation,我有一个任务,它从Web服务检索一些数据。只有当我打开一个页面(这是Xamarin.Forms)时,才应该调用Webservice,并且只有在没有其他版本的任务运行时才应该运行它——这部分工作正常 当我离开页面时,我想取消任务-我似乎无法让那部分工作。当OnAppearing(),OnDisappearing(),在Web服务返回数据之前点击OnAppearing(),日志只写“任务已尝试启动…”,这意味着任务没有被取消。相反,当调用OnDisappearing()`时,任务应该被取消 我试着按

我有一个任务,它从Web服务检索一些数据。只有当我打开一个页面(这是Xamarin.Forms)时,才应该调用Webservice,并且只有在没有其他版本的任务运行时才应该运行它——这部分工作正常

当我离开页面时,我想取消任务-我似乎无法让那部分工作。当
OnAppearing()
OnDisappearing()
,在Web服务返回数据之前点击
OnAppearing(),日志只写“任务已尝试启动…”,这意味着任务没有被取消。相反,当调用
OnDisappearing()`时,任务应该被取消

我试着按照StackOverflow上发布的一些示例进行操作,但似乎不起作用,我也不太明白

我的代码如下:

一经出现:

private Task task;
CancellationTokenSource tokenSource = new CancellationTokenSource();

protected override void OnAppearing()
{
    base.OnAppearing();

    if (task != null && (task.Status == TaskStatus.Running || task.Status == TaskStatus.WaitingToRun || task.Status == TaskStatus.WaitingForActivation))
    {
        Debug.WriteLine("Task has attempted to start while already running");
    }
    else
    {
        Debug.WriteLine("Task has began");

        var token = tokenSource.Token;
        task = Task.Run(async () =>
        {

            await GetDataAsync();
            /* EDIT: This is what I originally posted, but doesn't work so have commented it out
            while (!token.IsCancellationRequested)
            {
                await GetDataAsync();
            }
             */
       }, token);
   }      
}
OnDisappearing:

protected override void OnDisappearing()
{
    base.OnDisappearing();
    Debug.WriteLine("Page dissapear");
    tokenSource.Cancel();
    Debug.WriteLine("Task Cancelled");
}
GetData方法

public async Task GetData()
{
    WebAPI api = new WebAPI();

    try
    {
        Device.BeginInvokeOnMainThread(() =>
        {
            PageLoading();
        });

        string r = await api.GetProfileStatus(token);
        Device.BeginInvokeOnMainThread(async () =>
        {
           if (r == "OK")
           {
                GetDataSuccess();
           }
        }
     }
     catch (Exception e)
     {
        // log exception
     }
}

你在错误的地方做了正确的检查:

var token = tokenSource.Token;
task = Task.Run(async () =>
{
    while (!token.IsCancellationRequested)
    {
        await GetDataAsync();
    }
}
在这里开始任务,然后在循环中一次又一次地开始。正确的做法是检查
GetData
中的令牌,如果可能,进一步检查
api
变量。在这种情况下,您可以根据需要取消服务呼叫

旁注:

  • 使您的事件处理程序
    异步
    ,不要将您的工作包装在
    任务中。运行
  • 使您的
    GetData
    任务
    可以实际返回调用代码的状态,然后可以删除
    BeginInvokeMainThread
    ,因为
    Wait
    将在异步操作后恢复上下文
因此,您的代码如下所示:

protected override async void OnAppearing()
{
    base.OnAppearing();

    if (task != null && (task.Status == TaskStatus.Running || task.Status == TaskStatus.WaitingToRun || task.Status == TaskStatus.WaitingForActivation))
    {
        Debug.WriteLine("Task has attempted to start while already running");
    }
    else
    {
        Debug.WriteLine("Task has began");

        var token = tokenSource.Token;
        PageLoading();
        var r = await GetDataAsync(token);
        if (r == "OK")
        {
            GetDataSuccess();
        }
   }      
}

public async Task GetDataAsync(CancellationToken token)
{
    WebAPI api = new WebAPI();
    if (token.IsCancellationRequested)
    {
        token.ThrowIfCancellationRequested();
    }

    try
    {
        return await api.GetProfileStatus(token);
    }
    catch (Exception e)
    {
        // log exception and return error
        return "Error";
    }
}

GetData从哪里获得令牌?它和上面的一样吗?@Steve下次给你的代码适当的空格,它会让你的代码更容易理解readable@SamiKuhmonen我不确定。我以为传递到“Task.Run(async()=>…”中的令牌就是令牌?真的不太熟悉。@johnny5 OK注意到-谢谢。删除
任务。Run
-这是不必要的,因为GetData(async)已经是异步的,所以不需要在另一个任务中包装它-并提供GetData(async)使用取消令牌。取消的方式和效果取决于GetProfileStatus的实现方式。您好,谢谢!我将试一试,看看效果如何。我不确定OnAppearing是否可以标记为async,因为它是从Xamarin.Forms继承来的。这就是为什么我使用Task.Run。看起来这确实有效,并更改了OnAppearing同样也要感谢async。
async
不是方法签名的一部分,而
async void
仅适用于事件处理程序:)