Январь 2016

Том 31, номер 1

Windows 10 - Применение OneDrive REST API в UWP-приложении

Лоран Буньон | Январь 2016

Исходный код можно скачать по ссылке

Продукты и технологии:

OneDrive, REST, OAuth, Windows 10, Universal Windows Platform

В статье рассматриваются:

  • использование OneDrive при создании универсальных приложений;
  • принципы работы REST API;
  • применение OAuth и возможное использование операций файловой системы;
  • выполнение таких операций, как доступ к папке App и преобразование ссылки на какой-либо элемент в общую для друзей.

В предыдущих инфраструктурах, таких как в Windows Phone 8, группа OneDrive предоставляла SDK, который был довольно удобен в использовании, но не давал разработчику особой свободы. Например, механизм входа был всего один и реализовался только через встроенный элемент управления «кнопка», у которого разработчик не мог изменить ни внешний вид, ни поведение. Но самое неприятное было в том, что этот предопределенный механизм не позволял сделать соответствующий код общим между платформами.

Но теперь группа OneDrive предоставляет современный REST API на основе HTTP-запросов (GET, POST, PUT и др.). Это гибкий способ взаимодействия с гигантским файловым хранилищем в облаке и создания кросс-платформенного кода, используя общепринятые методы написания общего кода, способного выполняться на всех платформах Windows и даже на платформах iOS и Android с применением Xamarin.

В этой первой из двух статей будет показано, как использовать новый OneDrive API для создания приложений Universal Windows Platform (UWP). Сначала мы изучим, как работает REST API и как разработчики должны взаимодействовать с ним. Вы увидите, как пользователь может войти в систему, используя OAuth, и как могут быть задействованы операции файловой системы (просмотр папок, получение информации о файлах, получение содержимого файлов, загрузка файлов и т. д.). Вы также узнаете, как выполнять дополнительные операции, такие как обращение к папке App и преобразование ссылки на какой-либо элемент в общую для друзей.

В следующей статье я расскажу о новой Portable Class Library (PCL) от группы OneDrive, которая инкапсулирует описанные здесь операции в удобную библиотеку. Ее можно добавлять к вашим UWP-приложениям, а также применять в других поддерживаемых инфраструктурах вроде ASP.NET, Xamarin.iOS, Xamarin.Android или Xamarin.Forms.

Примечание В дополнение к PCL, которую можно использовать на платформах Xamarin.Android и Xamarin.iOS, группа OneDrive также предоставляет «родные» SDK для этих двух платформ.

Код примера

Вы можете скачать код примера с galasoft.ch/s/msdnonedrive. Он демонстрирует, как простое UWP-приложение может задействовать низкоуровневый REST API для выполнения операций в сервисе OneDrive. Чтобы проиллюстрировать простоту портирования кода, приложение-пример также реализовано для Xamarin.Android, и те же принципы применимы к другим платформам.

Вникаем в REST API

REST API использует HTTP как транспортный протокол и полагается на его методы (GET, POST, PUT, DELETE и т. д.) и стандартные коды ошибок (200 Success, 400 Bad request, 500 Server error и др.). Входная точка каждого API доступна через уникальный URI, который также может иметь параметры. В некоторых случаях для отправки информации сервису и получения результата можно использовать простой метод GET, но возможно создание и более сложных запросов с передачей некоторых объектов, сериализованных в JSON, методом POST.

REST API становится все более распространенным, и разработчики должны быть только рады этому, так как он предлагает ясный способ взаимодействия с веб-сервисами. Самое важное, что он делает возможным создание портируемых компонентов на C# и их применение на всех поддерживаемых платформах. Другое колоссальное преимущество в том, что HTTP основан на передаче текста и что запросы могут легко проходить через брандмауэры (сетевые экраны) и прокси-серверы.

Однако взаимодействие с низкоуровневыми HTTP-методами может показаться требующим массы усилий, особенно разработчикам, не знакомым с последними достижениями в асинхронном программировании. Создание асинхронного клиента, использующего обратные вызовы, было не лучшим опытом для разработчиков, поскольку могли возникать проблемы с глубоким вложением и синхронизацией потоков. К счастью, две относительно недавние разработки значительно упростили это для программистов на C#: компонент HttpClient и ключевые слова async и await. Например, обратиться к папке OneDrive Music теперь сводится к формированию URI и отправке GET-запроса:

var uri = new Uri(
  "https://api.onedrive.com/v1.0/drive/special/music");
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
  new AuthenticationHeaderValue("Bearer", AccessToken);
var json = await client.GetStringAsync(uri);

Конечный JSON-код можно десериализовать (с помощью библиотеки JSON.NET, например), чтобы получить .NET-объект, используемый в приложении. Этот код (нужно признать, что без обработки входа и ошибок) показывает, как сложная операция становится простой и текучей (fluid). Кроме того, этот код будет без проблем выполняться на любой платформе, поддерживаемой HttpClient, к числу которых относятся Windows Presentation Foundation (WPF), ASP.NET, Windows 10, Xamarin и др.

Регистрация вашего приложения

Прежде чем выдавать вызовы к OneDrive API, вы должны зарегистрировать свое приложение в OneDrive Dev Center, сконфигурировать его и получить ключ Client ID. Механизм регистрации описан по ссылке bit.ly/1GPBaWL.

При регистрации нового приложения обязательно откройте страницу API Settings и установите Mobile or desktop client app в Yes. Остальные настройки можно оставить по умолчанию. Затем получите Client ID со страницы App Settings и сохраните его для дальнейшего использования.

Важно понимать различные термины и то, для чего нужен каждый идентификатор.

  • Client ID (идентификатор клиента) Это уникальный идентификатор вашего UWP-приложения. У вас может быть несколько клиентских приложений, подключенных к сервисам Microsoft под одним и тем же Client ID, но, в целом, рекомендуется использовать по одному Client ID на каждое приложение. Client ID связывается с такой информацией об UWP-приложении, как его название, значок и т. д. Client ID генерируется при создании приложения и никогда не меняется.
  • Client Secret (секрет клиента) Это уникальный идентификатор, генерируемый при создании UWP-приложения. Однако этот код может изменяться в течение жизненного цикла приложения. Скажем, если вы считаете, что Client Secret был взломан, вы можете сгенерировать новый идентификатор, обновить свои приложения, и попытки хакерских приложений получить доступ будут отклоняться. Заметьте, что Client Secret обычно используется только серверными приложениями.
  • User ID и Password (идентификатор пользователя и пароль) При входе у пользователя запрашивается имя и пароль. Благодаря OAuth взаимодействие при входе происходит только между пользователем и OneDrive без знания самим клиентским приложением. На практике это делается с помощью WebView, в котором отображается диалог входа.
  • Access Token (маркер доступа) Когда пользователь успешно входит, сервис аутентификации возвращает Access Token. Этот маркер действует только в течение определенного времени (60 минут), после чего пользователь должен снова выполнить вход. Этот маркер должен передаваться с каждым запросом для подтверждения того, что пользователь аутентифицирован. Этот режим аутентификации называется Token Flow в документации.
  • Refresh Token (маркер обновления) Этот маркер может быть запрошен приложением и сохранен для обновления Access Token на случай, если срок его действия истек. Это может быть полезно, если ваше приложение используется в фоновом режиме длительное время и должно периодически обновлять данные без взаимодействия с пользователем. Этот режим аутентификации называется CodeFlow, и он описан по ссылке bit.ly/1MQ3KOb. В этой статье я буду применять только Token Flow, который легче в реализации.

Эксперименты с применением пробного маркера

Если вы хотите быстро опробовать несколько REST-запросов без предварительной реализации аутентификации, OneDrive Dev Center позволяет получить пробный маркер (trial token), действующий в течение часа, и его можно использовать следующим образом:

  • перейти по ссылке bit.ly/1MQ3KOb;
  • найти раздел Try it now и щелкнуть кнопку Get Token;
  • при необходимости зарегистрируйтесь и подтвердите, что вы авторизуете Dev Center для доступа к вашей учетной записи OneDrive;
  • после успешного входа пробный маркер появится в основном веб-окне;
  • создайте новое UWP-приложение с именем TrialOneDrive;
  • откройте MainPage.xaml и добавьте кнопку с именем TrialButton;
  • откройте MainPage.xaml.cs и добавьте обработчик событий Click для кнопки TrialButton (рис. 1). Заметьте, что этот обработчик событий должен использовать ключевое слово async, так как все операции в OneDrive являются асинхронными;
  • в коде на рис. 1 замените строку «YOUR TRIAL TOKEN» пробным маркером, который вы скопировали с веб-сайта Dev Center. Не копируйте слова «Authorization: bearer»!
  • поместите точку прерывания в последнюю строку обработчика событий, чтобы наблюдать за значением переменной json;
  • запустите приложение и щелкните кнопку;
  • наблюдайте за извлекаемым JSON-кодом в окне Watch. У вас должна появиться возможность видеть такую информацию о своей папке Music, как ее название, дата создания, дата последней модификации, количество дочерних элементов, идентификатор папки (который впоследствии можно использовать в различных операциях в файловой системе), имя пользователя, вошедшего в систему, и т. д.
TrialButton.Click += async (s, e) =>
{
  var uri = new Uri(
    "https://api.onedrive.com/v1.0/drive/special/music");
  var client = new HttpClient();
  client.DefaultRequestHeaders.Authorization = new
    AuthenticationHeaderValue("Bearer", "YOUR TRIAL TOKEN");
  var json = await client.GetStringAsync(uri);
};

Помните, что срок действия пробного маркера истекает через час, поэтому не забудьте получить новый, если захотите продемонстрировать это приложение своему боссу!

Аутентификация с помощью OAuth

Теперь, когда у вас есть зарегистрированное приложение и вы понимаете важные термины, можно реализовать аутентификацию. Ниже перечислены этапы этой реализации (которые также проиллюстрированы на рис. 2).

  1. Пользователь инициирует аутентификацию, например щелчком какой-то кнопки.
  2. Приложение проверяет, доступен ли Access Token.
  3. Если да, приложение уже аутентифицировано и пользователь может перейти к следующей операции. Если Access Token отсутствует, приложение переходит на XAML-страницу, содержащую WebView.
  4. XAML-страница задает начальный URL для WebView, чтобы загрузить страницу конечной точки аутентификации. XAML-страница также подписывается на событие WebNavigationCompleted от WebView, чтобы отслеживать трафик в этом элементе управления. Вы узнаете, как структурируется начальный URL далее в этой статье.
  5. WebView загружает HTML с конечной точки аутентификации.
  6. Пользователь вводит свое имя и пароль на HTML-странице аутентификации. Заметьте, что это взаимодействие происходит строго между пользователем и сервером OneDrive. XAML-страница действует просто как контейнер.
  7. Пользователь нажимает HTML-кнопку, которая передает форму серверу аутентификации. Если пользователь указал двухфакторную аутентификацию, показываются дополнительные страницы для ее обработки.
  8. Если удостоверения правильны, сервер аутентификации перенаправляет WebView на специальный URL, по которому сообщается об успешном входе. Этот URL также имеет Access Token как один из своих параметров строки запроса. XAML-страница обнаруживает, что произошло перенаправление, и может разобрать Access Token из нового URL от WebView.
  9. Страница Authentication разбирает Access Token из URI перенаправления.
  10. Приложение возвращается обратно на исходную XAML-страницу. Access Token сохраняется для последующих запросов.

Примечание Хотя важно понимать, как работает OAuth, к счастью, у разработчиков для Windows 10 есть более простая альтернатива — WebAuthenticationBroker. В этой статье я использую «низкоуровневый» механизм OAuth, а о WebAuthenticationBroker расскажу в следующей статье.

Рабочий процесс OAuth
Рис. 2. Рабочий процесс OAuth

1 Click Щелчок
6 Log In Вход
9 Get Token from URI Получение маркера из URI
Main Page Основная страница
Auth Аутентификация
3 Navigate Переход
Auth Page Страница аутентификации
Webview WebView
4 Set URI Subscribe Подготовка URI-запроса Subscribe
2 Is Authenticated? No g Navigate to Auth Page Аутентифицирован?
Нет — переход на страницу аутентификации
10 Go Back Возврат
5 Get HTML Auth Page Получение HTML-страницы аутентификации
7 Post User Credentials Отправка удостоверений пользователя
8 Redirect to Successful URI Перенаправление на URI, сообщающий об успехе
One-Drive Service Сервис OneDrive

Разбираемся в областях

После входа пользователя приложение должно информировать сервис OneDrive о диапазоне средств, которые ему понадобятся. Для этого в URL аутентификации указываются области (scopes). В настоящее время сервис поддерживает следующие области.

  • Single sign-on (единый вход) Wl.signin.
  • Offline access (автономный доступ) Wl.offline_access. Позволяет вашему приложению получить Refresh Token. Эта область игнорируется при использовании аутентификации Token Flow.
  • Readonly access (доступ только для чтения) Onedrive.readonly. Предоставляет вашему приложению доступ к файлам и папкам только для чтения. Если приложение попытается модифицировать файл или загрузить новый файл, сервис вернет код ошибки «403 Forbidden».
  • Readwrite access (доступ для чтения и записи) Onedrive.readwrite. Предоставляет вашему приложению доступ к файлам и папкам для чтения и записи.
  • AppFolder Onedrive.appfolder. Позволяет вашему приложению обращаться к так называемой App Folder (папке App). Об этой особой папке я подробнее расскажу далее в этой статье. Заметьте, что эта область выдается автоматически, когда вы запрашиваете область readwrite. Однако запрос appfolder явным образом приведет к упоминанию этой области в диалоге.

Рис. 3. Запуск аутентификации

if (!_service.CheckAuthenticate(
  async () =>
  {
    var dialog = new MessageDialog(
      "You are authenticated!", "Success!");
    await dialog.ShowAsync();
    Frame.GoBack();
  },
  async () =>
  {
    var dialog = new MessageDialog(
      "Problem when authenticating!", "Sorry!");
    await dialog.ShowAsync();
    Frame.GoBack();
  }))
{
  Frame.Navigate(typeof (AuthenticationPage));
};

После того как пользователь вводит свои удостоверения на веб-странице аутентификации, появляется диалог, предлагающий подтвердить разрешения, запрашиваемые приложением (рис. 4). Пользователь может в любой момент передумать и отозвать некоторые из разрешений. Для этого ему надо войти в свою учетную запись на веб-сайте OneDrive, перейти в Security and Privacy и выбрать ссылку Manage permissions под Apps & Services. В этом примере вы будете всегда запрашивать единый вход и права доступа readwrite и appfolder.

Подтверждение аутентификации
Рис. 4. Подтверждение аутентификации

Создание начального URL

URL, используемый для запуска процесса аутентификации, должен нести информацию о самом приложении, запрашиваемых средствах (областях), режиме аутентификации и URI перенаправления.

Режимом аутентификации может быть Token или Code. В этой статье и примере я использовал режим Token, при котором пользователь должен подтверждать вход при каждом новом запуске приложения или через один час. Звучит раздражающе, но на деле пользователю надо лишь подтвердить вход нажатием кнопки Yes в диалоге аутентификации, как показано на рис. 4.

URI перенаправления — это адрес, на который сервис OneDrive будет перенаправлять приложение при успешном входе. В случае веб-приложения это URI страницы в вашем приложении, и он настраивается в OneDrive Dev Center на вкладке API Settings. Но в случае UWP-приложения вы должны оставить это поле пустым. Вместо этого вы полагаетесь на предопределенный URI перенаправления:

htt://login.live.com/oauth20_desktop.srf

Собираем все воедино

Теперь, когда вы понимаете, как работает аутентификация по OAuth, давайте рассмотрим некоторый код. Вы можете следовать за мной в простом примере, щелкнув кнопку Authenticate.

Вы используете класс OneDriveService, реализованный в PCL. Экземпляр OneDriveService создается в App.xaml.cs, и вы передаете ему Client ID.

Сначала ваш MainPage спрашивает сервис OneDrive, аутентифицирован ли он, т. е. присутствует ли уже Access Token. Вы передаете два делегата в вызове метода CheckAuthenticate: Action, который будет вызван, если аутентификация успешна, и Action, вызываемый в случае ошибки.

Если сервис еще не аутентифицирован, MainPage использует свойство Frame для перехода на AuthenticationPage, как показано на рис. 5. Это простая XAML-страница с WebView, который занимает весь экран, где пользователь будет вводить свои имя и пароль, а затем подтверждать вход.

Рис. 5. Код для AuthenticationPage

public sealed partial class AuthenticationPage
{
  private readonly OneDriveService _service;

  public AuthenticationPage()
  {
    InitializeComponent();

    _service = ((App)Application.Current).ServiceInstance;

    Loaded += (s, e) =>
    {
      var uri = _service.GetStartUri();
      Web.Navigate(uri);
    };

    Web.NavigationCompleted += (s, e) =>
    {
      if (_service.CheckRedirectUrl(e.Uri.AbsoluteUri))
      {
        _service.ContinueGetTokens(e.Uri);
      }
    };

    Web.NavigationFailed += (s, e) =>
    {
      _service.ContinueGetTokens(null);
    };
  }
}

После загрузки страницы вы получаете URI аутентификации от OneDriveService:

https://login.live.com/oauth20_authorize.srf?client_id=
000000004C169646&scope=wl.signin+onedrive.readwrite+onedrive.
appfolder&response_type=token&redirect_uri=https%3A%2F%2Flogin.
live.com%2Foauth20_desktop.srf

Как уже пояснялось, этот URI несет всю необходимую информацию, такую как Client ID, Client Secret, Scope, Redirect URI и др.

Заметьте, что WebView будет перенаправлен несколько раз до получения Access Token. Вот почему вы должны всегда проверять URI перенаправления в событии NavigationCompleted в WebView. Когда URI oauth20_desktop.srf наконец обнаруживается, OneDriveService извлечет маркер доступа из параметров в строке запроса. В этой строке передается дополнительная информация (срок действия, тип маркера, область, идентификатор пользователя и т. д.), но здесь вы просто игнорируете ее. Сокращенный Redirect URI с Access Token выглядит так:

https://login.live.com/oauth20_desktop.srf?lc=1033#access_
token=EwB4Aq1D...1iiZAE%3d&token_type=bearer&expires_in=3600&
scope=wl.signin%20onedrive.readwrite%20onedrive.appfolder%20
onedrive.readonly&user_id=8e5323e8b7c7a0928d03e10811531234

После аутентификации пользователя приложение может взаимодействовать с файлами и папками. В этой статье я сосредоточусь на нескольких операциях, но расширить приложение для включения дополнительных сервисов довольно легко, как только вы поймете принципы.

Папка Root

Прежде всего я расскажу о папке Root. Эта папка уникальна в вашем OneDrive и является родительской по отношению к любому из других элементов, создаваемых вами.

Согласно документации OneDrive, получить папку Root можно следующим запросом: GET /drive/root. Этот запрос вернет JSON-ответ, как описано по ссылке bit.ly/1M5w4NV. JSON-ответ можно десериализовать, а информацию из него — использовать для дальнейших запросов.

Структура папок и файлов К этому моменту важно понимать, как структурирована файловая система. OneDrive полагается на систему аспектов (facets), предоставляя информацию о файлах и папке. Например, файл может быть и Image (изображение), и Photo (снимок) с такой дополнительной информацией, как ширина/высота для Image и Camera Model для Photo). В следующем списке перечислены аспекты, доступные в настоящее время, и некоторые из их наиболее важных свойств:

  • Item (Name, ID, URL скачивания, ссылка на родителя и т. д.);
  • Folder (количество дочерних элементов);
  • File;
  • Audio (альбом, артист, битрейт, длительность, название и др.);
  • Image (ширина, высота);
  • Photo (марка и модель камеры, дата и время снимка);
  • Video (длительность, битрейт, ширина, высота).

Когда вы закачиваете новый файл в OneDrive, он автоматически анализируется, и к нему добавляются некоторые метаданные. Например, документ Word — это просто File. Но снимок, сделанный камерой, является не только File, но и Photo и Image. Каждый из этих аспектов несет дополнительную информацию о файле, как показано в списке выше.

Разбирая JSON, полученный от сервиса OneDrive, вы можете сопоставлять эти аспекты с C#-классами. Анализируя JSON, вы можете весьма легко выяснить, является некий элемент папкой (Folder), файлом (File), изображением (Image), видео (Video) или чем-то еще. Скажем, на рис. 6 показан фрагмент JSON-ответа для папки Root. Как видите, свойство folder несет информацию о количестве дочерних элементов папки. Если бы вы получили информацию о Photo, то обнаружили бы свойства image и photo, заполненные данными о ширине (Width) и высоте (Height), а также о марке (Camera Make) и модели камеры (Camera Model) соответственно.

Рис. 6. JSON-ответ для папки Root

{
  "createdBy": {
    "user": {
      "displayName": "Laurent Bugnion",
      "id": "fb0d8f9700498123"
    }
  },
  "createdDateTime": "2010-11-27T17:09:25.513Z",
  "id": "FB0D8F97004979CD!ABC",
  "lastModifiedBy": {
    "user": {
      "displayName": "Laurent Bugnion",
      "id": " fb0d8f9700498123"
    }
  },
  "lastModifiedDateTime": "2015-10-04T14:36:36.217Z",
  "name": "root",
  "size": 178558187077,
  "webUrl": "https://onedrive.live.com/?cid=fb0d8f9700498123",
  "folder": {
    "childCount": 18
  }
}

Когда вы закачиваете новый файл в OneDrive, он автоматически анализируется, и к нему добавляются некоторые метаданные.

В приложении-примере, представленном в этой статье, вы десериализуете JSON в классы, содержащиеся в папке Response, которые сопоставляются с системой аспектов.

Теперь, когда вы знаете, как устроены ответы, можно легко обращаться к информации папки Root, используя следующий код:

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
  new AuthenticationHeaderValue("Bearer", AccessToken);

var uri = new Uri("https://api.onedrive.com/v1.0/drive/root");
var json = await client.GetStringAsync(uri);
var rootFolder = JsonConvert.DeserializeObject<
  ItemInfoResponse>(json);

Чтобы увидеть этот код в действии, вы можете запустить простой пример и нажать сначала кнопку Authenticate, а затем кнопку Get Root Folder.

Получение дочерних элементов папки  Как и на рис. 6, ответ содержит только метаданные о папке. Вы знаете, сколько дочерних элементов имеется в папке, но, чтобы получить список этих элементов, нужно выполнить один или более запросов. Здесь тоже поможет документация OneDrive: вам нужен GET-запрос для /drive/items/{item-id}/children, как показано на рис. 7.

Рис. 7. Получение списка дочерних элементов

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
  new AuthenticationHeaderValue("Bearer", AccessToken);

var request = string.Format(
  "/drive/items/{0}/children", info.Id);
var uri = new Uri("https://api.onedrive.com/v1.0" + request);
var json = await client.GetStringAsync(uri);

var response = JsonConvert.DeserializeObject<
  ParseChildrenResponse>(json);
return response.Value;

JSON на рис. 7 десериализуется в класс с именем ParseChildrenResponse. Он снова сопоставляется с JSON-ответом, который обертывает список дочерних элементов в JavaScript-массив value. Класс ParseChildrenResponse представлен на рис. 8.

Рис. 8. Класс ParseChildrenResponse

public class ParseChildrenResponse
{
  public IList<ItemInfoResponse> Value
  {
    get;
    set;
  }

  [JsonProperty("@odata.nextLink")]
  public string NextLink
  {
    get;
    set;
  }
}

Поскольку каждый дочерний элемент является ItemInfoResponse, вы знаете, как обрабатывать его и понять, что он собой представляет: папку, файл, снимок, аудиофайл или др.

Заметьте: если вы хотите избежать двух вызовов для получения информации о папке и заполнения списка ее дочерних элементов, можно использовать следующий запрос, который делает все это одним вызовом:

GET /drive/items/root?expand=children

Разбиение на страницы Когда вы обращаетесь к папке с большим количеством элементов, ответ, отправляемый сервисом OneDrive, может оказаться неполным и потребовать разбиения на страницы (paging). По умолчанию сервис возвращает список максимум из200 элементов. Если просматриваемая вами папка содержит больше дочерних элементов, к списку добавляется свойство @odata.nextLink (его можно увидеть и на рис. 8). Это свойство содержит URI для следующего запроса, который приложение должно выполнить, чтобы получить следующую «страницу». В UWP-приложении можно выбрать либо немедленный вызов сервиса для получения следующей страницы с элементами (что будет нормально работать, так как длинные списки виртуализуются), либо отображение кнопки More и реализацию навигации по страницам в приложении.

Просмотр подпапки Как только у вас есть идентификатор папки, вы можете легко просматривать эту папку, используя следующий запрос:

GET /drive/items/{item-id}

Это удобно, когда вы уже располагаете идентификатором нужной папки, но иногда этой информации у вас нет. Другой синтаксис позволяет получать информацию о папке, используя путь к ней относительно корня. Этот синтаксис используется в коде на рис. 9.

Рис. 9. Просмотр подпапки по пути

var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
  new AuthenticationHeaderValue("Bearer", AccessToken);

var request = string.Format("/drive/root:/{0}", path);

var uri = new Uri("https://api.onedrive.com/v1.0" + request);

var json = await client.GetStringAsync(uri);
var result = JsonConvert.DeserializeObject<
  ItemInfoResponse>(json);
return result;

Папка App

В OneDrive есть несколько особых папок, таких как Music, Documents, Photos и т. д. Одна из особых папок появилась недавно: App. Эта особая папка, доступная вашему приложению и предназначенная, например, для сохранения перемещаемых параметров (roaming settings), резервных копий загрузок на сервер (upload backups) и др. Заметьте, что папка App никоим образом не защищена и не скрыта. По сути, она находится в папке Apps, расположенной прямо в корне OneDrive вашего пользователя. Папка App приложения имеет то же название, что и приложение OneDrive, введенное при регистрации с целью получения Client ID. Заметьте, что название приложения может быть локализовано на разных языках, исходя из параметров приложения OneDrive. Пользователь имеет полный доступ к папке App через веб-сайт OneDrive или любое приложение и при желании даже может удалить ее.

До введения концепции папки App приложения сохраняли (и многие из них до сих пор сохраняют) свои настройки и другие файлы в корне OneDrive или в собственной папке. Применение папки App для хранения этих элементов гораздо понятнее и более удобно с точки зрения пользовательской среды (UX). Согласно документации OneDrive (bit.ly/1MBUkS2), запрос на получение информации о папке App выглядит так:

GET /drive/special/approot

Как видите, папку App легко реализовать в любом приложении!

Скачивание файла

Какая польза была бы от OneDrive, если бы вы не могли загружать в него файлы или скачивать их? В этом и следующем разделах вы увидите, насколько легко выполнять эти крайне важные операции.

Чтобы скачать содержимое файла, OneDrive создает DownloadUrl, сохраняемый как свойство в ответе элемента (item response). Однако этот URL действует лишь в течение краткого времени, поэтому, если информация о файле кешировалась, вам может понадобиться первым делом снова получить эту информацию от сервиса (рис. 10).

Рис. 10. Скачивание содержимого файла

public async Task<Stream> RefreshAndDownloadContent(
  ItemInfoResponse model,
  bool refreshFirst)
{
  var client = new HttpClient();
  client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", AccessToken);

  // Обновляем информацию об элементе
  if (refreshFirst)
  {
    var request = string.Format("/drive/items/{0}", model.Id);

    var uri = new Uri("https://api.onedrive.com/v1.0"
      + request );

    var json = await client.GetStringAsync(uri);
    var refreshedItem =
      JsonConvert.DeserializeObject<ItemInfoResponse>(json);
    model.DownloadUrl = refreshedItem.DownloadUrl;
  }

  var response = await client.GetAsync(model.DownloadUrl);
  var stream = await response.Content.ReadAsStreamAsync();
  return stream;
}

Получив поток содержимого файла, вы можете обрабатывать его локально, сохранять и т. д. В простом примере пользователю предлагается указать место, где будет сохранен файл; при этом используется FileSavePicker.

Загрузка файла

Аналогично загрузка (закачка) файла тоже весьма проста, как только вы получите поток файла. В Windows 10 это можно сделать с помощью экземпляра StorageFile, например используя FileOpenPicker. Прочитав поток, вы можете загрузить его в OneDrive. Согласно документации, для этого вам потребуется операция PUT:

PUT /drive/items/{parent-id}:/{filename}:/content

HttpClient поддерживает метод PUT с помощью экземпляра HttpContent. В данном случае, поскольку вы имеете дело с неструктурированным файловым потоком, можно задействовать экземпляр StreamContent. Если вы хотите лишь сохранить какой-нибудь текстовый файл, то можете применить StringContent и т. д.

Другая информация, которую вы должны передать сервису, — идентификатор папки, в которой будет сохранен файл. В простом примере на рис. 11 parentId передается методу загрузки. Заметьте, что операция PUT возвращает JSON-контент, описывающий новую информацию о файле в OneDrive, такую как его идентификатор, веб-URL, URL скачивания и т. п.

Рис. 11. Загрузка содержимого файла

var content = new StreamContent(stream);
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
  new AuthenticationHeaderValue("Bearer", AccessToken);

var uri = new Uri(
  "https://api.onedrive.com/v1.0"
  + string.Format(
    "/drive/items/{0}:/{1}:/content",
    parentId,
    fileName));

var response = await client.PutAsync(uri, content);
var json = await response.Content.ReadAsStringAsync();

var result = JsonConvert.DeserializeObject<
  ItemInfoResponse>(json);
return result;

Помимо простой загрузки, описанной здесь, OneDrive API также предлагает возобновляемые закачки и загрузки, разбитые на множество частей (multipart uploads) с разным синтаксисом. Простая загрузка годится для файлов, размер которых не превышает 100 Мб. Если размер файла больше, загляните в документацию по ссылке bit.ly/1PB31Cn.

Получение уникальной ссылки

Последняя операция, которую я продемонстрирую здесь, — получение уникальной «общей» ссылки для какого-либо элемента. Эта операция удобна для отправки уникальной ссылки другу по электронной почте, в SMS, через социальные сети и др. На рис. 12 показано, как получить эту информацию по идентификатору элемента. В этом примере вы получаете ссылку на файл, который вы только что загрузили в предыдущей демонстрации.

Рис. 12. Получение общей ссылки

public async Task<LinkResponseInfo> GetLink(
  LinkKind kind, string fileId)
{
  // LinkKind идентифицирует view или edit

  var client = new HttpClient();
  client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", AccessToken);

  var request = string.Format("/drive/items/{0}/
    action.createLink", fileId);
  var uri = new Uri("https://api.onedrive.com/v1.0" + request);

  var requestJson = JsonConvert.SerializeObject(
    new RequestLinkInfo
    {
      Type = kind.ToString().ToLower()
    });

  var content = new StringContent(
    requestJson,
    Encoding.UTF8,
    "application/json");

  var response = await client.PostAsync(uri, content);

  var result = JsonConvert.DeserializeObject<LinkResponseInfo>(
    await response.Content.ReadAsStringAsync());
  return result;
}

Согласно документации, запрос немного отличается от GET-запросов, которые вы выдавали ранее, так как сервису нужна более подробная информация. Запрособщей ссылки выглядит такis: POST /drive/items/{item-id}/action.createLink. Данные нужно отправить сервису как JSON-фрагмент с типом ссылки: view илиedit, например{ "type": "view" }.

Заключение

Есть несколько дополнительных операций, которые я не описывал в этой статье, такие как удаление файла, обновление содержимого файла и синхронизация. Но в целом, все операции следуют одному и тому же шаблону и могут выполняться, используя HttpClient, HTTP-методы и JSON. Благодаря достижениям в асинхронном программировании в Microsoft .NET Framework подобные операции чрезвычайно текучи (fluid) и легко реализуются в любой поддерживаемой инфраструктуре, включая не только Windows 10, но и WPF, Windows Phone, Xamarin.iOS, Xamarin.Android и т. д. Ввиду такой простоты использования нет никаких препятствий для организации той или иной формы взаимодействия с облаком в ваших UWP-приложениях, например чтобы создать резервную копию контента или переместить настройки. В следующей статье вы увидите, как PCL, недавно выпущенная группой OneDrive, поможет еще больше упростить это взаимодействие.


Лоран Буньон (Laurent Bugnion) — старший директор IdentityMine Inc., одной из ведущих компаний и «золотого» партнера, работающего с технологиями Microsoft. Живет в Цюрихе (Швейцария). Его книга «Silverlight 4 Unleashed» (Sams, 2010) — расширенное продолжение «Silverlight 2 Unleashed» (2008). Пишет для нескольких издательств, уже девятый год подряд является Microsoft MVP и второй год занимает должность регионального директора Microsoft. Автор широко известных инфраструктур MVVM Light for Windows, WPF, Xamarin и одного из популярных справочных курсов Pluralsight по MVVM Light. С ним можно связаться через его блог galasoft.ch.

Выражаю благодарность за рецензирование статьи экспертам Коррадо Кавалли (Corrado Cavalli) из Gaia и Райену Греггу (Ryan Gregg) из Microsoft.