Async : IProgress and Immutability

In the previous post, we explored IProgress interface briefly and understood how it helps us in reporting progress. It seemed a perfect fit choice, with little chances of human errors. However, there are things one needs to be aware of to ensure you do not end up with unrecognizable errors.

Let’s rewrite the code in earlier post with slight modification.

async Task InvokeLongRunningMethod()
{
  Console.WriteLine("Initiating method call");
  var progress = new Progress<MessageObject>(ProgressDisplay);
  var result = await LongRunningMethod(progress);
  Console.WriteLine($"Completed executing method with result = {result}");
}


void ProgressDisplay(MessageObject update)
{
  Console.WriteLine(update.Message);
}

async Task<bool> LongRunningMethod(IProgress<MessageObject> progress)
{
  var test = new MessageObject();
  for(int i=0;i<100;i++)
  {
    if(i%10==0)
   {
     test.msg = $"In Progress : {i}%";
     progress.Report(test);
   }
  }

  return true;
}

public class MessageObject
{
       public string Message{get;set;}
}

We have created a MessageObject Class, which has been passed on as the parameter for the IProgress interface parameter type T. So how does this change the equation. Let’s run the code and watch the output first.

Initiating method call
Completed executing method with result = True
In Progress : 90%
In Progress : 90%
In Progress : 90%
In Progress : 90%
In Progress : 90%
In Progress : 90%
In Progress : 90%
In Progress : 90%
In Progress : 90%
In Progress : 90%

As observed in the output, the progress shows 90% each time. Isn’t that strange. Well, not quite if you think a bit more. The IProgress.Report method calls are asynchronous and needn’t be quite completed at that moment. Since the object instance changes before the Report method is called again, the previous call too ends with same value. For this very reason, you need to ensure that the T parameter type is always immutable or you create a separate copy each time Report is invoked.

Advertisements

Reporting Progress in Async Method

Quite often you would need to provide some kind of progress from your long running asynchronous method, especially if it process multiple activities. Though there might be multiple ways to achieve it, Microsoft provides us with a simple and efficient interface IProgress, which enables us to achieve the result. Let’s hit the code straightaway.

void Main()
{
   InvokeLongRunningMethod();
}

async Task InvokeLongRunningMethod()
{
   Console.WriteLine("Initiating method call");
   var progress = new Progress<string>(ProgressDisplay);
   var result = await LongRunningMethod(progress);
   Console.WriteLine($"Completed executing method with result = {result}");
}


void ProgressDisplay(string update)
{
   Console.WriteLine(update);
}

async Task<bool> LongRunningMethod(IProgress<string> progress)
{

  for(int i=0;i<100;i++)
  {
     await Task.Delay(100);
     if(i%10==0)  progress.Report($"In Progress : {i}%");

  }
  return true;
}

The output would be

Initiating method call
In Progress : 0%
In Progress : 10%
In Progress : 20%
In Progress : 30%
In Progress : 40%
In Progress : 50%
In Progress : 60%
In Progress : 70%
In Progress : 80%
In Progress : 90%
Completed executing method with result = True