Friday, 11 October 2019

Task CancellationToken .net C# example, Solution for - how to kill long running task in C#?

Here we are exploring a small demo, of how cancellation token play a  big role in managing the long running task. Most of the time we use Task, Async, await to take the advantage of system thread to boost performance. But some time we ignore Task Cancellation to implement.




By exploring both  console application and web Api in Dotnet core, we will see how cancellation token affect the running task. You can get full running demo from GitHub demo.

So let's start with console application,

using System;
using System.Threading;
using System.Threading.Tasks;
 
namespace TaskCancellationByToken.ConsoleDemo
{
    class Program
    {
        public static Task PrintWithCancellationToken(int count, CancellationToken cancellationToken)
        {
            for (int i = 1; i <= count; i++)
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    break;
                }
                else
                {
                    Console.Write(nameof(PrintWithCancellationToken));
                    Console.WriteLine(i);
                }
                Thread.Sleep(10);
            }
 
            return Task.FromResult(0);
        }
        
        public static Task Print(int count)
        {
 
            for (int i = 1; i <= count; i++)
            {
                Console.Write(nameof(Print));
                Console.WriteLine(i);
                Thread.Sleep(10);
            }
            return Task.FromResult(0);
 
        }
 
        static void Main(string[] args)
        {
            Parallel.Invoke(async () =>
                await Print(500),
                async () =>
                {
                    using (CancellationTokenSource cTokenSource = new CancellationTokenSource())
                    {
                        var keyBoardTask = Task.Run(() =>
                        {
                            Console.WriteLine("Press enter to cancel");
                            Console.ReadKey();
 
                            // Cancel the task
                            cTokenSource.Cancel();
                        });
 
                        await PrintWithCancellationToken(500, cTokenSource.Token);
                    }
                }
                );
            Console.WriteLine("Hello World!");
        }
    }
}

Here in console application

  • We have 2 methods that print Counting value from 1 to 500 along with method name.
  • Printing is happening with some sleep interval, so that task will take some time to execute.
  • We are running both the task parallel.
Now what we want that while we press enter one task should be stop in between, and so we used cancellation token.

Let's verify output here will see PrintWithCancellationToken stopped in between.





Now moving toward 2nd demo which is Dotnet core web Api.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
 
namespace TaskCancellationByToken.WebApiDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
        [HttpGet("WithCancellationToken")]
        public ActionResult<IEnumerable<string>> Get(CancellationToken cancellationToken)
        {
            List<string> lst = new List<string>();
            for (int i = 1; i <= 10; i++)
            {
                //cancellationToken.ThrowIfCancellationRequested(); //System.OperationCanceledException: 'The operation was canceled.'
                if (cancellationToken.IsCancellationRequested)
                {
                    Debug.WriteLine("Task Cancled");
                    break;
                }
                else
                {
                    var value = "value" + i;
                    lst.Add(value);
                    Debug.WriteLine(value);
                }
                Thread.Sleep(1000);
            }
            Debug.WriteLine("Task Finished");
            return lst;
        }
 
        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            List<string> lst = new List<string>();
            for (int i = 1; i <= 10; i++)
            {
                var value = "value" + i;
                lst.Add(value);
                Debug.WriteLine(value);
                Thread.Sleep(1000);
            }
            Debug.WriteLine("Task Finished");
            return lst;
        }
    }
}

Here in dotnet core web api,

  • We have 2 action for ValueController and like same console application we have 2 action here one use cancellation token and 2nd doesn't use cancellation token.
  • We will be verifying output in browser and output tab in visual studio for debug information.

If we verify normal action execution even if we stop or abort http request from browser entire execution process running till end.


 But if we have implemented Cancellation token for API and we cancel it from browser or from client, execution terminate in background as well.




Now you can evaluate how useful it is to implement Cancellation token with Task in web API.