Вызов асинхронных API в C# и Visual Basic

Универсальная платформа Windows (UWP) включает много асинхронных API, позволяющих вашему приложению сохранить способность отвечать, когда выполняется работа, требующая много времени. В этом разделе описывается применение асинхронных методов UWP при программировании на языках C# или Microsoft Visual Basic.

При применении асинхронных API-интерфейсов приложению не требуется ждать завершения трудоемких операций. Например, приложение, скачивающее информацию из Интернета, может ожидать получения данных несколько секунд. Если информация получается синхронным методом, приложение блокируется до момента возврата данных методом. Приложение при этом не отвечает на действия пользователя и кажется зависшим, что может встревожить пользователя. Благодаря асинхронным API, предоставляемым UWP, приложение сохраняет способность отвечать на запросы пользователя при выполнении длительных операций.

У большинства асинхронных API в UWP нет синхронных аналогов, поэтому необходимо понимать, как следует использовать асинхронные API в приложении UWP на языках C# или Visual Basic. Здесь мы покажем, как вызывать асинхронные API UWP.

Использование асинхронных API

По соглашению асинхронным методам даются имена, которые заканчиваются на «Async». Асинхронные API обычно вызываются в ответ на действие пользователя, например при нажатии кнопки. Вызов асинхронного метода в обработчике событий — один из простейших способов использования асинхронных API. Здесь в качестве примера используется оператор await.

Предположим, некоторое приложение перечисляет заголовки записей в блоге из определенного веб-сайта. В приложении имеется Button (кнопка), которую пользователи нажимают для получения заголовков. Заголовки отображаются в TextBlock. Когда пользователи нажимают данную кнопку, важно, чтобы приложение сохраняло способность отвечать, пока ожидается информация от веб-сайта блога. Для обеспечения этой способности UWP предоставляет асинхронный метод SyndicationClient.RetrieveFeedAsync для скачивания веб-канала.

Здесь дан пример кода для получения из блога списка его записей с помощью вызова асинхронного метода SyndicationClient.RetrieveFeedAsync и ожидания получения результата.

// Put the keyword async on the declaration of the event handler.
private async void Button_Click_1(object sender, RoutedEventArgs e)
{

    Windows.Web.Syndication.SyndicationClient client = new SyndicationClient();

    Uri feedUri
        = new Uri("http://windowsteamblog.com/windows/b/windowsexperience/atom.aspx");

    try
    {
        SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri);

        // The rest of this method executes after await RetrieveFeedAsync completes.
        rssOutput.Text = feed.Title.Text + Environment.NewLine;

        foreach (SyndicationItem item in feed.Items)
        {
            rssOutput.Text += item.Title.Text + ", " +
                             item.PublishedDate.ToString() + Environment.NewLine;
        }
    }
    catch (Exception ex)
    {
        // Log Error.
        rssOutput.Text =
            "I'm sorry, but I couldn't load the page," +
            " possibly due to network problems." +
            "Here's the error message I received: "
            + ex.ToString();
    }
}
' Put the keyword Async on the declaration of the event handler.
Private Async Sub Button_Click_1(sender As Object, e As RoutedEventArgs)
    Dim client As New Windows.Web.Syndication.SyndicationClient()
    Dim feedUri As New Uri("http://windowsteamblog.com/windows/b/windowsexperience/atom.aspx")

    Try
        Dim feed As SyndicationFeed = Await client.RetrieveFeedAsync(feedUri)

        ' The rest of this method executes after the await operation completes.
        rssOutput.Text = feed.Title.Text & vbCrLf

        For Each item In feed.Items
            rssOutput.Text += $"{item.Title.Text}, {item.PublishedDate.ToString()}{vbCrLf}"
        Next

    Catch ex As Exception
        ' Log Error.
        rssOutput.Text = "I'm sorry, but I couldn't load the page," &
                         " possibly due to network problems." &
                         "Here's the error message I received: " &
                          ex.ToString()
    End Try

End Sub

Есть несколько важных замечаний о приведенном выше примере. Во-первых, в строке SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri) используется оператор await вместе с вызовом асинхронного метода RetrieveFeedAsync. Можно представить себе, что оператор await сообщает компилятору о том, что вы вызываете асинхронный метод, в результате чего компилятор выполняет дополнительную работу за вас. Во-вторых, объявление обработчика событий включает ключевое слово async. Это ключевое слово необходимо включить в объявление любого метода, в котором используется оператор await.

В этом разделе мы не будем углубляться в детали того, что компилятор делает с оператором await. Однако давайте изучим, что делает приложение асинхронным и способным отвечать на запросы. Рассмотрим, что происходит при использовании синхронного кода. Например, предположим, что есть синхронный метод SyndicationClient.RetrieveFeed. (Такого метода нет, но представим, что он существует.) Если ваше приложение включает строку SyndicationFeed feed = client.RetrieveFeed(feedUri) вместо SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri), выполнение приложения останавливается, пока не будет доступно возвращаемое значение RetrieveFeed. А пока приложение ожидает завершения выполнения метода, оно не может реагировать на другие события, например на еще одно событие Click. То есть приложение будет блокировано, пока метод RetrieveFeed не вернет значение.

Однако если вызывать client.RetrieveFeedAsync, данный метод инициирует извлечение и немедленно возвращает значение. При использовании оператора await с методом RetrieveFeedAsync приложение временно завершает работу обработчика событий. Затем оно может обрабатывать любые другие события, пока RetrieveFeedAsync выполняется асинхронно. Это позволяет приложению сохранить способность реагировать на действия пользователя. Когда метод RetrieveFeedAsync завершает работу и становится доступен SyndicationFeed, приложение повторно запускает обработчик событий с момента его закрытия после SyndicationFeed feed = await client.RetrieveFeedAsync(feedUri) и завершает оставшуюся часть метода.

Интересная особенность использования оператора await заключается в том, что код с его участием не очень отличается от кода с применением воображаемого метода RetrieveFeed. Асинхронный код в C# или Visual Basic можно записать тремя способами без оператора await, однако полученный код больше подчеркивает механику асинхронного выполнения. Поэтому асинхронный код сложен в написании, понимании и обслуживании. Оператор await позволяет получить преимущества асинхронного приложения без создания сложного кода.

Типы возврата и результаты асинхронных API

Если перейти по ссылке RetrieveFeedAsync, можно заметить, что тип возврата RetrieveFeedAsync не SyndicationFeed, а IAsyncOperationWithProgress<SyndicationFeed, RetrievalProgress>. С точки зрения простого синтаксиса асинхронный API возвращает объект, содержащий результат. Несмотря на то, что принято представлять асинхронный метод как метод, поддерживающий ожидание, и это иногда удобно, оператор await фактически работает с возвращаемым значением метода, а не с самим методом. При применении оператора await вы получаете результат вызова GetResult в объекте, возвращенном этим методом. В примере SyndicationFeed является результатом RetrieveFeedAsync.GetResult().

При использовании асинхронного метода можно проверить сигнатуру, чтобы увидеть, что вы получите по окончании ожидания возврата значения метода. Все асинхронные API UWP возвращают один из следующих типов:

Тип результата асинхронного метода тот же, что и у параметра типа TResult. У типов без TResult нет результата. Данный результат можно представлять как void. В Visual Basic процедура Sub эквивалентна методу с типом возврата void.

В таблице ниже даются примеры асинхронных методов и перечисляются тип возврата и тип результата для каждого из них.

Асинхронный метод Возвращаемый тип Тип результата
SyndicationClient.RetrieveFeedAsync IAsyncOperationWithProgress<SyndicationFeed, RetrievalProgress> SyndicationFeed
FileOpenPicker.PickSingleFileAsync Файл хранилища IAsyncOperation<> StorageFile
XmlDocument.SaveToFileAsync IAsyncAction void
InkStrokeContainer.LoadAsync IAsyncActionWithProgress<UInt64> void
DataReader.LoadAsync DataReaderLoadOperation, пользовательский класс результатов, который реализует IAsyncOperation<UInt32> UInt32

 

Асинхронные методы, определенные в .NET for UWP apps, имеют тип возврата Task или Task<TResult>. Методы, возвращающие Task, аналогичны асинхронным методам UWP, которые возвращают IAsyncAction. В каждом случае результат асинхронного метода — void. Тип возврата Task<TResult> подобен IAsyncOperation<TResult>, так как у результата асинхронного метода при выполнении задачи тот же тип, что и у параметра типа TResult. Дополнительную информацию об использовании .NET for UWP apps и задач см. в статье Общая информация о .NET для приложений среды выполнения Windows.

Обработка ошибок

При использовании оператора await для получения результатов из асинхронного метода блок try/catch позволяет обрабатывать ошибки, возникающие в асинхронных методах, так же, как и для синхронных методов. В примере выше метод RetrieveFeedAsync и оператор await заключены в блок try/catch для обработки ошибок при вызове исключений.

Когда асинхронные методы вызывают другие асинхронные методы, любой асинхронный метод, приводящий к вызову исключения, распространяется на внешние методы. Это означает, что в самый внешний метод можно поместить блок try/catch, чтобы перехватывать ошибки для вложенных асинхронных методов. Это аналогично перехвату исключений для синхронных методов. Однако вы не можете использовать await в блоке catch.

Совет Начиная с C# в Microsoft Visual Studio 2005, вы можете использовать await в блоке catch .

Сводка и дальнейшие действия

Здесь показан простейший способ вызова асинхронного метода, когда асинхронные API вызываются в обработчике событий. Этот способ также применим, когда асинхронный метод вызывается в переопределенном методе, который возвращает void или Sub в Visual Basic.

Сталкиваясь с асинхронными методами в UWP, важно помнить следующее.

  • По соглашению асинхронным методам даются имена, которые заканчиваются на «Async».
  • Объявление любого метода, в котором используется оператор await, должно быть помечено ключевым словом async.
  • Когда приложение находит оператор await, оно сохраняет способность взаимодействовать с пользователем, пока выполняется асинхронный метод.
  • В результате ожидания значения асинхронный метод возвращает объект, содержащий результат. В большинстве случаев результат, содержащийся в возвращаемом значении — это то, что используется, а не само возвращаемое значение. Тип значения, содержащегося в результате, можно найти, взглянув на тип возврата асинхронного метода.
  • Благодаря использованию асинхронных API и шаблонов async часто можно улучшить скорость отклика приложения.

При выполнении примера из данного раздела выводится текст следующего вида.

Windows Experience Blog
PC Snapshot: Sony VAIO Y, 8/9/2011 10:26:56 AM -07:00
Tech Tuesday Live Twitter #Chat: Too Much Tech #win7tech, 8/8/2011 12:48:26 PM -07:00
Windows 7 themes: what’s new and what’s popular!, 8/4/2011 11:56:28 AM -07:00
PC Snapshot: Toshiba Satellite A665 3D, 8/2/2011 8:59:15 AM -07:00
Time for new school supplies? Find back-to-school deals on Windows 7 PCs and Office 2010, 8/1/2011 2:14:40 PM -07:00
Best PCs for blogging (or working) on the go, 8/1/2011 10:08:14 AM -07:00
Tech Tuesday – Blogging Tips and Tricks–#win7tech, 8/1/2011 9:35:54 AM -07:00
PC Snapshot: Lenovo IdeaPad U460, 7/29/2011 9:23:05 AM -07:00
GIVEAWAY: Survive BlogHer with a Sony VAIO SA and a Samsung Focus, 7/28/2011 7:27:14 AM -07:00
3 Ways to Stay Cool This Summer, 7/26/2011 4:58:23 PM -07:00
Getting RAW support in Photo Gallery & Windows 7 (…and a contest!), 7/26/2011 10:40:51 AM -07:00
Tech Tuesdays Live Twitter Chats: Photography Tips, Tricks and Essentials, 7/25/2011 12:33:06 PM -07:00
3 Tips to Go Green With Your PC, 7/22/2011 9:19:43 AM -07:00
How to: Buy a Green PC, 7/22/2011 9:13:22 AM -07:00
Windows 7 themes: the distinctive artwork of Cheng Ling, 7/20/2011 9:53:07 AM -07:00