Search code examples
c#.netwindows-store-appsasync-awaittask-parallel-library

how to wait for task.run


I am writing a windows store app and needs some help on Task.Run method. I am calling service to retrieve data from a service; because I want to cancel the task when internet is disconnected I am passing CancellationToken

await Task.Run(async () => await Download1(), cts.Token); 

There is another download method which should run after this above task is finished so I am using await. Both the tasks write to same files so I want to make sure that they do not run in parallel.

await Task.Run(async () => await Download2(), cts.Token); 

The issue is that above task 2 starts without task 1 is finished and so both task run in parallel. What I am doing wrong? Please advise.

Download1 looks like this:-

 public async Task Download1()
        {
         await   Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                         async () =>
                         {
                             Status = "Downloading!";
                             var ListSetupTasks = new List<SetupView>();
                             foreach (var setup in AllSetupTasks.Setup)
                             {
                                 ListSetupTasks.Add(new SetupViewModel(setup));
                             }

                             IEnumerable<Task> downloadTasksQuery = from setup in ListSetupTasks where setup.TaskType == TaskType.Web select _masterlistrepository.GetTask(setup, false, datetime, branch);
                             Task[] downloadTasks = downloadTasksQuery.ToArray();
                             await Task.WhenAll(downloadTasks);

                             IEnumerable<Task> FinalTasksQuery = from setup in ListSetupTasks where setup.TaskType == TaskType.Web select _masterlistrepository.GetTask(setup, false);
                             foreach (var task in FinalTasksQuery)
                             {
                                 await task;
                             }
                         });

        }

The CancellationToken is used like this:-

async void NetworkChanged(object sender, NetworkConnectionStatusChangedEventArgs e)
        {
            if (e.Value == false && LoadingData == true)
            {

             await   Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                            async () =>
                            {
                                await _alertmessageservice.ShowAsync("", "Network error. Please retry!");
                                cts.Cancel();
                            });

            }
        }

Solution

  • You use the CoreDispatcher.RunAsync which accepts a DispatchedHandler. DispatchedHandler has this signature:

    public delegate void DispatchedHandler()
    

    So when you pass in an async lambda it will end up being async void. That makes it impossible to await as there's no task being returned. This means that everything after an await in your lambdas will run on a different thread concurrently.

    You shouldn't be passing an async delegate to that method.


    As a side note, passing a CancellationToken doesn't enable to automatically stop the operation. It can only stop the operation before it starts or if you're observing the token somewhere inside the operation.

    So, to actually use the CancellationToken Download should accept use it which makes the Task.Run redundant:

    await Download1Async(cts.Token);