Click here to Skip to main content
13,797,304 members
Click here to Skip to main content
Add your own
alternative version

Tagged as

Stats

5.9K views
161 downloads
5 bookmarked
Posted 23 Jan 2018
Licenced CPOL

IO Bound Async / Await Task Example with Cancellation Option

, 23 Jan 2018
Rate this:
Please Sign up or sign in to vote.
Brief example on how to use an IO Bound Async / Await process

Introduction

This article shows a small example on how to use the Async/Await pattern in a simple WPF-based application, and how the user can Cancel the current started thread by means of a CancellationToken.

Using the Code

We will first start to show how the demo application works, and next we will go through the technical implementation details in a step by step manner.

The User Interface

The application is quite simple. The user fills in the full path where the text file resides, clicks the Get button and the content of the textfile is loaded into the main screen (if found), else an error messagebox will be shown. To prove that the processing (read) of the textfile executes async, the user can click the "+" button while processing the input file. This will show an integer value augmenting with 1 in the main-screen. While processing the file, a % processing message is shown in the main screen. Finally, to show the use of CancellationTokens when the user "hits" the Cancel button, the running thread (task) will be interrupted and a cancellation message will be shown to the user!

Before Moving to the Code Behind ...

Remark 1: Use of Regions ...

IMHO, it is always a good idea to group similar code into regions, I usually use next regions:

  • Private Storage: Variable declarations
  • C'tor: Constructor code
  • Private Interface: All private methods, subdivided between UIEventhandlers and ApplicationLogic
  • Public Interface: All code accessible from outside (+ eventually Protected and Internal sections if needed...).

Remark 2: Writing Code in UI-Code-Behind

For the sake of simplicity... all event-handling and application-logic in this sample has been written in the code-behind of the main-form. Although this is ok for demo-purposes, it should be omitted in production coding. Instead, all application and event-handling logic should be extracted from the UI code behind and put in so-called View-Model classes, adapting the MVVM (Model-View-ViewModel) pattern.

Explaining the Code-Behind

Private Storage

#region Private Storage

private int _counter;
CancellationTokenSource _cts;

#endregion Private Storage

The _counter variable will be used to update the counter when the user clicks the + button. This is just mentioned to show the reader that the UI-interface stays responsive while the background thread is running (task which is executing the read-async after the user activated the Get button).

Get File Content event-handling Method

private async void buttonGetFile_Click(object sender, RoutedEventArgs e)
{
    try
    {
        _cts = new CancellationTokenSource();
        textBlockResult.Text = string.Empty;
        labelPlus.Content = string.Empty;
        labelProgress.Content = string.Empty;

        buttonGetFile.IsEnabled = false;
        textBlockResult.Text = await GetFileContentAsync(textBoxFileName.Text, _cts.Token);

    }
    catch (OperationCanceledException exCancel)
    {
        MessageBox.Show(exCancel.Message);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
    finally
    {
        buttonGetFile.IsEnabled = true;
    }
}

This method will call a method which reads data from a file in an async manner. In the call to GetFileContentAsync(...), which reads the content of a file on disk, send the CancellationTokenSource.Token property of _cts as an argument. The Token property propagates a cancellation message if cancellation is requested. Add a catch block that displays a message if the user chooses to cancel the file-read operation. While this IO bound background thread is running, the UI is still responsive to user input (click the + button to prove this).

UI Stays Responsive During Execution of Background Thread

private void buttonPlus_Click(object sender, RoutedEventArgs e)
{
    labelPlus.Content = _counter++.ToString();
}

During the execution of the background-thread (started when user provided a correct URL to a phsycial file on local disk and started the IO bound retrieval process by hitting the Get button in the UI), UI stays responsive and user can click the + button which will augment the counter.

The Implementation of the async Method

private async Task<string> GetFileContentAsync(string fileName, CancellationToken ct)
{
    // mimic long running process ...
    for(int i = 0; i <= 100; i++)
    {
        if (!ct.IsCancellationRequested)
        {
            // mimic some long running process ...
            await Task.Delay(50);
            // update ui, we use dispatch to update the ui thread
            this.Dispatcher.Invoke(() => SetProgress(i.ToString(), fileName));
        }
    }

    using (StreamReader reader = new StreamReader(fileName))
    {
        if (!ct.IsCancellationRequested)
        {
            string fileContent = await reader.ReadToEndAsync();
            return fileContent;
        }
        throw new OperationCanceledException
             ($"File-read-async of {fileName} has been canceled by user !");
    }
}

private void SetProgress(string progress, string fileName)
{
   labelProgress.Content = $"file {fileName} - {progress} % processed ...";
}

private void buttonCancel_Click(object sender, RoutedEventArgs e)
{
   if (_cts != null)
      _cts.Cancel();
}

The code is quit straightforward, the method provides a fileName and CancellationToken as input argument will return a Task of string as return value. Once the Task is completed, control will be returned to the calling method (buttonGetFile_Click) and the result will be shown in the UI. Due to the async executing context, the UI will stay responsive for the user todo other stuff mainwhile the background process runs ... If the user hits the Cancel button, then the ongoing thread will be canceled. Remark: Because the async reading process doesn't take ling to complete, I've mimick a long-during-process by introducing a delay. Also note that we inform the UI-Thread on each interval. We need to execute the this.Dispatcher.Invoke(...) method because our running background process is running on a different thread than the UI-thread.

Points of Interest

Please note that the above mentioned example is an IO bound async process, this, in contrast to CPU-bound async processes may be handled differently, more specifically we should (in contrast to CPU bound) try to give the thread back to the thread-pool while executing the IO intensive tasks. This way, the thread can be re-used by the windows-scheduler to handle different operations. To keep things simple, I did not include this behavoir in this simple example, but please check (among-others) next URL on this concept: return-task-threads-back-to-the-thread-pool.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Emmanuel Nuyttens
Architect REALDOLMEN
Belgium Belgium
Working in the IT-Branch for more then 20 years now. Starting as a programmer in WinDev, moved to Progress, shifted to .NET since 2003. At the moment i'm employed as a Microsoft Dynamics AX Interfacing Architect at RealDolmen (Belgium). In my spare time, i'm a die hard mountainbiker and together with my sons Jarne and Lars, we're climbing the hills in the "Flemish Ardens" and the wonderfull "Pays des Collines". I also enjoy "a p'tit Jack" (Jack Daniels Whiskey) or a "Duvel" (beer) for "l'après VTT !".

You may also be interested in...

Comments and Discussions

 
QuestionAre you really cancelling an async file read? Pin
George Swan23-Jan-18 23:46
memberGeorge Swan23-Jan-18 23:46 
AnswerRe: Are you really cancelling an async file read? Pin
BillWoodruff24-Jan-18 2:55
mentorBillWoodruff24-Jan-18 2:55 
AnswerRe: Are you really cancelling an async file read? Pin
wkempf25-Jan-18 6:19
memberwkempf25-Jan-18 6:19 
GeneralRe: Are you really cancelling an async file read? Pin
George Swan25-Jan-18 10:32
memberGeorge Swan25-Jan-18 10:32 
GeneralRe: Are you really cancelling an async file read? Pin
wkempf25-Jan-18 12:26
memberwkempf25-Jan-18 12:26 
AnswerRe: Are you really cancelling an async file read? Pin
Emmanuel Nuyttens27-Jan-18 4:42
memberEmmanuel Nuyttens27-Jan-18 4:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web05 | 2.8.181207.3 | Last Updated 23 Jan 2018
Article Copyright 2018 by Emmanuel Nuyttens
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid