User Tools

Site Tools


notes:uwp:iasync_interfaces

IAsync Interfaces in Windows Runtime

In Windows Runtime, an object returned from an asynchronous operation always implements one of the IAsync interfaces. The following IAsync interfaces are defined in Windows Runtime:

  • IAsyncAction
  • IAsyncActionWithProgress<TProgress>
  • IAsyncOperation<TResult>
  • IAsyncOperationWithProgress<TResult,TProgress>

All of the above interfaces inherit from IAsyncInfo.

The asynchronous operation completes when:

  • the operation completes successfully
  • the operation is canceled
  • the operation fails

Once the operation completes (not necessarily successfully), Windows Runtime invokes the callback method.

Example: Read a file asynchronously and invoke a callback method. In this example the async method GetFileAsync returns an object of type IAsyncOperation<StorageFile>:

public void ReadFile()
{
    // Read a file asynchrnonously. 'operation' represents the pending asynchronous operation.
    IAsyncOperation<StorageFile> operation = KnownFolders.MusicLibrary.GetFileAsync("music.mp3");
 
    // Assign a delegate of a callback method.
    operation.Completed = OnCompleted;
 
    // To cancel the pending operation call operation.Cancel().
}
 
// OnCompleted is our callback method. The 'operation' parameter is a reference to the object returned by 
// the KnownFolders.MusicLibrary.GetFileAsync method.
// OnCompleted may be invoked by a UI thread or another thread.
private void OnCompleted(IAsyncOperation<StorageFile> operation, AsyncStatus status)
{
    if (status == AsyncStatus.Canceled)
    {
        // process cancellation ... 
    }
    else
    {
        try
        {
            StorageFile file = operation.GetResults();  // throws an exception if operation failed          
 
            // process the file ...
        }
        catch (Exception ex)
        {
            // ... 
        }
    }
 
    // Clean up the IAsyncOperation object.
    operation.Close();
}

We can re-write the above code using the C#'s await keyword:

StorageFile file = await KnownFolders.MusicLibrary.GetFileAsync("music.mp3");
-or-
StorageFile file = KnownFolders.MusicLibrary.GetFileAsync("music.mp3").AsTask().GetAwaiter().GetResult();  

As in the previous example, the GetFileAsync method returns an object that implements the IAsyncOperation<StorageFile> interface. This time, however, the compiler looks for a GetAwaiter method on the returned object. It finds one of the GetAwaiter overloads defined as an extension method:

static TaskAwaiter GetAwaiter(this IAsyncAction source); 
static TaskAwaiter GetAwaiter<TProgress>(this IAsyncActionWithProgress<TProgress> source);
static TaskAwaiter<TResult> GetAwaiter<TResult>(this IAsyncOperation<TResult> source);
static TaskAwaiter<TResult> GetAwaiter<TResult, TProgress>(this IAsyncOperationWithProgress<TResult, TProgress> source); 

The above extension methods are defined in the class WindowsRuntimeSystemExtensions located in the System namespace. They return a TaskAwaiter object which is awaited in the code. Once the asynchronous operation completes, the TaskAwaiter object ensures that the code continues executing via the SynchronizationContext that is associated with the original thread. Then the thread queries the Task's Result property, which returns the result.

Example: Write a line of text to a file:

public static void WriteLine(string message)
{
    const string LogFilename = "log.txt";
 
    StorageFolder folder = ApplicationData.Current.LocalFolder;
    IAsyncOperation<StorageFile> createFileOp = 
          folder.CreateFileAsync(LogFilename, CreationCollisionOption.OpenIfExists);
    createFileOp.Completed = (IAsyncOperation<StorageFile> operation, AsyncStatus status) =>
    {
        if (status == AsyncStatus.Completed)
        {
            StorageFile file = operation.GetResults();
            IAsyncAction writeTextAction = 
                FileIO.AppendTextAsync(file, message + Environment.NewLine,
                    Windows.Storage.Streams.UnicodeEncoding.Utf8);
        }
    };
}

Example: Read titles of atom feeds:

using System.Threading.Tasks;
using Windows.Web.Syndication;
...
List<string> feedTitles = new List<string>();
 
Task<string> feed1 = GetFeedAsync("http://example.org/2011/09/11/atom.aspx");
Task<string> feed2 = GetFeedAsync("http://example.org/2011/12/23/atom.aspx");
 
feedTitles.Add(await feed1);
feedTitles.Add(await feed2);
...
private async Task<string> GetFeedAsync(string feedUriString)
{
    Windows.Web.Syndication.SyndicationClient client = new SyndicationClient();
    Uri feedUri = new Uri(feedUriString);
 
    string feedTitle = "";
 
    try
    {
        SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri);
 
        if (feed.Title != null && feed.Title.Text != null)
        {
            feedTitle = feed.Title.Text;
        }
 
        return feedTitle;
    }
    catch (Exception exc)
    {
        return "ERROR: " + exc.Message;
    }
}
notes/uwp/iasync_interfaces.txt · Last modified: 2016/12/29 by admin