meataxe
meataxe

Reputation: 981

Wrap asynchronous calls with synchronous method

I have a 3rd party DLL with an asynchronous method that I want to wrap with another method that waits for its result.

I started writing a class to hide the functionality, but now I can't work out how to wait for Doc.Completed to be called by the DLL after this.version.DownloadFile(this) in Doc.Download.

The DLL calls InitTransfer, then OnProgressNotify a number of times, then Completed. OnError may be called at any stage, but Completed is always called last. I don't care about InitTransfer, OnProgressNotify or OnError.

I have read Asynchronous call in synchronous method and Turn asynchronous calls into synchronous but I don't understand how to apply the answers to this case.

I'm using C# 4.

public class Doc : SomeInterfaceFromTheDll
{
  private readonly IVersion version; // An interface from the DLL.

  private bool downloadSuccessful;

  public Doc(IVersion version)
  {
    this.version = version;
  }

  public bool Download()
  {
    this.version.DownloadFile(this);
    return ??? // I want to return this.downloadSuccessful after Completed() runs.
  }

  public void Completed(short reason)
  {
    Trace.WriteLine(string.Format("Notify.Completed({0})", reason));
    this.downloadSuccessful = reason == 0 ? true : false;
  }

  public void InitTransfer(int totalSize)
  {
    Trace.WriteLine(string.Format("Notify.InitTransfer({0})", totalSize));
  }

  public void OnError(string errorText)
  {
    Trace.WriteLine(string.Format("Notify.OnError({0})", errorText));    
  }

  public void OnProgressNotify(int bytesRead)
  {
    Trace.WriteLine(string.Format("Notify.OnProgressNotify({0})", bytesRead));
  }
}  

Upvotes: 0

Views: 833

Answers (1)

Iridium
Iridium

Reputation: 23721

This can be achieved using a ManualResetEvent as shown below. There are a few caveats though. The primary one being that this mechanism does not permit you to call Download() on the same Doc instance on multiple threads at the same time. If you need to do this, then a different approach may be required.

public class Doc : SomeInterfaceFromTheDll
{
  private readonly IVersion version; // An interface from the DLL.
  private readonly ManualResetEvent _complete = new ManualResetEvent(false);

  private bool downloadSuccessful;

  // ...

  public bool Download()
  {
    this.version.DownloadFile(this);
    // Wait for the event to be signalled...
    _complete.WaitOne();
    return this.downloadSuccessful;
  }

  public void Completed(short reason)
  {
    Trace.WriteLine(string.Format("Notify.Completed({0})", reason));
    this.downloadSuccessful = reason == 0;
    // Signal that the download is complete
    _complete.Set();
  }

  // ...
}  

Upvotes: 1

Related Questions