Create an Asynchronous Method [C#]

By Kelvin
Nov 07, 2018 563

This example shows how to create an asynchronous method conforming to the Event-based Asynchronous pattern.

This example is part of asynchronous method implementation series.

In this example, we create an asynchronous version of a method that processes a list of files.

[C#]

private void MyTask(string[] files)
{
  foreach (string file in files)
  {
    // a time consuming operation with a file (compression, encryption etc.)
    Thread.Sleep(1000);
  }
}

The asynchronous method implementation consists of the following members:

  • MyTaskWorker method – does the actual work
  • IsBusy property – indicates that an asynchronous operation is running
  • MyTaskAsync method – invokes the asynchronous operation
  • MyTaskCompleted­Callback method – called when MyTaskWorker completes
  • MyTaskCompleted event – notifies of the asynchronous operation completion.

Notice how members names are derived from the original method name. This is the recommended way.

MyTaskWorker method

This method is executed on background and does the actual work of the original synchronous method. In this example, it doesn't differ from the original method. Notice that we also provide a delegate definition for this method.

[C#]

private void MyTaskWorker(string[] files)
{
  foreach (string file in files)
  {
    // a time consuming operation with a file (compression, encryption etc.)
    Thread.Sleep(1000);
  }
}

private delegate void MyTaskWorkerDelegate(string[] files);

IsBusy property

This property indicates a running asynchronous operation. Implementation of this property is needed, when concurrent invocations of asynchronous operations are not supported.

[C#]

private bool _myTaskIsRunning = false;

public bool IsBusy
{
  get { return _myTaskIsRunning; }
}

MyTaskAsync method

This method invokes the asynchronous operation and immediately returns. If an asynchronous operation is already running, an InvalidOperati­onException is thrown.

[C#]

public void MyTaskAsync(string[] files)
{
  MyTaskWorkerDelegate worker = new MyTaskWorkerDelegate(MyTaskWorker);
  AsyncCallback completedCallback = new AsyncCallback(MyTaskCompletedCallback);

  lock (_sync)
  {
    if (_myTaskIsRunning)
      throw new InvalidOperationException("The control is currently busy.");

    AsyncOperation async = AsyncOperationManager.CreateOperation(null);
    worker.BeginInvoke(files, completedCallback, async);
    _myTaskIsRunning = true;
  }
}

private readonly object _sync = new object();

First, an AsyncOperation is created. This object is used by the worker thread to invoke client's event handlers on the proper thread or context for the given application model.

Next, the asynchronous operation is started in a separate thread by the BeginInvoke method. Besides the files parameter, the BeginInvoke method has two additional parameters:

  • A delegate of type AsyncCallback to a callback method that is called when the asynchronous operation completes.
  • A custom object that is stored in the AsyncState property of an IAsyncResult instance returned by the BeginInvoke method. The same instance of IAsyncResult is also passed to the callback method.

Be sure to throw no exceptions after the BeginInvoke statement.

MyTaskCompleted­Callback method

This method calls worker delegate's En­dInvoke method to finish the asynchronous operation and raises the MyTaskCompleted e­vent.

[C#]

private void MyTaskCompletedCallback(IAsyncResult ar)
{
  // get the original worker delegate and the AsyncOperation instance
  MyTaskWorkerDelegate worker =
    (MyTaskWorkerDelegate)((AsyncResult)ar).AsyncDelegate;
  AsyncOperation async = (AsyncOperation)ar.AsyncState;

  // finish the asynchronous operation
  worker.EndInvoke(ar);

  // clear the running task flag
  lock (_sync)
  {
    _myTaskIsRunning = false;
  }

  // raise the completed event
  AsyncCompletedEventArgs completedArgs = new AsyncCompletedEventArgs(null,
    false, null);
  async.PostOperationCompleted(
    delegate(object e) { OnMyTaskCompleted((AsyncCompletedEventArgs)e); },
    completedArgs);
}

First, the original worker delegate instance and the AsyncOperation object are obtained. Next, EndInvoke is called to free resources held by the asynchronous operation. At last, the MyTaskCompleted event is fired through the AsyncOperation object.

MyTaskCompleted event

This event is raised when the asynchronous operation is completed.

[C#]

public event AsyncCompletedEventHandler MyTaskCompleted;

protected virtual void OnMyTaskCompleted(AsyncCompletedEventArgs e)
{
  if (MyTaskCompleted != null)
    MyTaskCompleted(this, e);
}

Leave A Comment


{{i.FullName}}

{{i.Message}}

  • {{i.CreatedOn | jsonDate}}

RELATED VIDEOS

Youtube

Video's Name

Video's Name

By Kelvin
25/3/2015 1,200
Youtube

Video's Name

Video's Name

By Kelvin
25/3/2015 1,200
Youtube

Video's Name

Video's Name

By Kelvin
25/3/2015 1,200