(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Применение C++ REST SDK в приложениях Windows Store

Сридхар Подури

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

Продукты и технологии:
C++ REST SDK, OAuth
В статье рассматриваются:

  • предыдущий пример Win32-приложения;
  • варианты интеграции с Windows Runtime;
  • использование класса WebAuthenticationBroker;
  • создание цепочки асинхронных веб-запросов.

В предыдущей статье (msdn.microsoft.com/magazine/dn342869) я познакомил вас с C++ REST SDK и тем, как его можно использовать в Win32/MFC-приложениях. В этой статье мы обсудим, как C++ REST SDK можно интегрировать в приложения Windows Store. Одной из моих исходных целей в применении C++ REST SDK и класса аутентификации на основе OAuth было максимально полное использование стандартного C++ и лишь при необходимости взаимодействие со специфичными для платформы API. Кратко напомню суть предыдущей статьи.

  1. Код в классе аутентификации на основе OAuth использует только стандартные C++-типы - без специфичных для Windows типов.
  2. Код для выдачи веб-запросов к REST-сервису Dropbox использует типы из C++ REST SDK.
  3. Единственный специфичный для платформы код - это функция, которая запускает Internet Explorer, выполняет аутентификацию приложения и получает одобрение от портала Dropbox.

Я поставил те же цели в своем приложении Windows Store для поддержки аутентификации и загрузки файла в Dropbox. Я стремился написать максимально больше портируемого кода на C++ и взаимодействовать с Windows Runtime (WinRT) только при необходимости.

Проблемы с Win32-решением

Одним из крупных недостатков в предыдущем Win32-приложении была необходимость запуска внешнего приложения для выполнения процесса авторизации на основе OAuth. Это означало, что я должен был запускать Internet Explorer (можно было бы запускать и любой другой браузер), входить в Dropbox по своим удостоверениям, а затем выполнять необходимый рабочий процесс. Он проиллюстрирован на рис. 1 и 2.

Вход в Dropbox по моим удостоверениям до авторизации доступа приложения
Рис. 1. Вход в Dropbox по моим удостоверениям до авторизации доступа приложения

Успешная авторизация моего приложения на портале Dropbox
Рис. 2. Успешная авторизация моего приложения на портале Dropbox

Как видите, запуск внешнего приложения и предложение пользователям пройти рабочий процесс через внешнее приложение уводит фокус ввода из окна моего приложения. Как разработчик я также лишен стандартного механизма, через который мое приложение могло бы уведомляться о завершении этого рабочего процесса. При концентрации на асинхронном программировании и использовании C++ REST SDK, предназначенного для поддержки программирования на основе асинхронных задач, вынужденный запуск внешнего приложения со всей очевидностью является для меня неприятной ситуацией. Я исследовал подходы с применением именованных каналов (named pipes), проецируемых в память файлов (memory-mapped files) и т. д., но все эти подходы требуют создания другого приложения для хостинга экземпляра элемента управления "веб-браузер" и последующей записи значения, свидетельствующего об успехе, обратно через именованный канал, общую память или проецируемый в память файл. В итоге я остановился на использовании браузера для выполнения этой задачи, так как не хотел писать другую программу, которая обертывала бы элемент управления "веб-браузер".

Одним из крупных недостатков в предыдущем Win32-приложении была необходимость запуска внешнего приложения для выполнения процесса авторизации на основе OAuth.

Интеграция с Windows Runtime

Начав проектировать свое приложение под Windows Runtime, я рассмотрел несколько вариантов. Я вкратце расскажу о них здесь, а потом мы подробно обсудим выбранный мной подход.

  1. Используем активацию протокола и даем системе запустить подходящий процесс для обработки этого протокола, вызвав функцию Windows::System::Launcher::LaunchUriAsync. Это означает, что для URI на основе HTTPS операционная система запустит браузер по умолчанию. Это аналогично запуску Internet Explorer из Win32-примера, но с "двойной комиссией": мое приложение Windows Store станет фоновым процессом, браузер по умолчанию запустится в полноэкранном режиме, и в самом худшем случае мое приложение будет приостановлено на время выполнения пользователем рабочего процесса. Совершенно не годится!
  2. Интегрируем в приложение элемент управления WebView. Использование XAML-элемента WebView позволяет встроить всю навигацию по рабочему процессу в контекст моего приложения. Теоретически, я также могу получать уведомления о завершении процесса, слушая событие window.external.notify, генерируемое элементом управления WebView. Однако на практике это событие генерируется, только если веб-страница генерирует событие уведомления. В моем случае страница Dropbox, где выполняется процесс авторизации, такое событие не генерирует. Неприятная ситуация!
  3. Используем WebAuthenticationBroker в моем приложении. Продолжая копаться в Windows Runtime, я случайно наткнулся на класс WebAuthenticationBroker. Судя по всему, он мог бы помочь мне в выполнении процесса авторизации, и, действительно, я сумел создать всю необходимую функциональность на его основе. Прежде чем перейти к рассмотрению кода, позвольте мне пояснить некоторые детали, касающиеся WebAuthenticationBroker.

WebAuthenticationBroker

В мире подключенных приложений, чтобы получить согласие и одобрение пользователя, важно запрашивать его удостоверения через безопасный и доверяемый механизм. Никто не хочет быть разработчиком, чьи приложения допускают утечку удостоверений пользователя или оказываются уязвимыми к скрытым атакам с целью похищения информации о пользователе. Windows Runtime включает ряд API и необходимые технологии, позволяющие разработчику безопасно передавать удостоверения пользователя. WebAuthenticationBroker - одно из таких средств, которое дает возможность приложениям Windows Store использовать протоколы аутентификации и авторизации через Интернет, такие как OAuth и OpenID. Как же это работает в моем приложении-примере для Dropbox?

  1. Я выдаю начальный асинхронный запрос к Dropbox, который возвращает маркер и секрет для моего приложения. Этот начальный запрос передается через функцию oAuthLoginAsync.
  2. Как только функция oAuthLoginAsync возвращает управление, я конструирую в продолжении последовательности URI, где должен начаться процесс авторизации. В своем примере я определил начальный URI как строковую константу:
  1. const std::wstring DropBoxAuthorizeURI = 
  2.   L"https://www.dropbox.com/1/oauth/authorize?oauth_token=";
  1. Затем я формирую URI HTTP-запроса, дописывая маркер, возвращенный Dropbox.
  2. В качестве дополнительного шага я конструирую параметр с URI обратного вызова, обращаясь к функции WebAuthenticationBroker::GetCurrentApplicationCallbackUri. Заметьте, что я не использовал URI обратного вызова в своем настольном приложении, так как этот параметр не обязателен и я полагался на Internet Explorer в выполнении задачи авторизации.
  3. Теперь строка запроса готова, и я могу выдать запрос. Вместо использования класса http_client или интерфейса IHttpWebRequest2 из C++ REST SDK для вызовов веб-сервиса я вызываю функцию WebAuthenticationBroker::AuthenticateAsync.
  4. Функция WebAuthenticationBroker::AuthenticateAsync принимает два параметра: перечисление WebAuthenticationOptions и URI. Перегруженный экземпляр той же функции принимает перечисление WebAuthenticationOptions и два URI, по одному из которых начинается процесс аутентификации, а по другому - заканчивается.
  5. Я использую первую версию функции AuthenticateAsync и передаю значение None для перечисления WebAuthenticationOptions, а также URI, сформированный для моего веб-запроса.
  6. WebAuthenticationBroker размещается между моим приложением и системой. В точке, где я вызываю AuthenticateAsync, он создает системный модальный диалог, который является модальным для моего приложения.
  7. Брокер подключает окно веб-хоста к созданному им модальному диалоговому окну.
  8. Затем брокер выбирает выделенный процесс контейнера приложений, отделенный от контейнера, в котором выполняется мое приложение. Это также приводит к очистке любых сохраненных данных в моем приложении.
  9. Далее брокер начинает процесс аутентификации в этом только что выбранном контейнере приложения и переходит к URI, указанному функцией AuthenticateAsync.
  10. Когда пользователи взаимодействуют с веб-страницами, брокер проверяет каждый URL для указанного URI обратного вызова.
  11. Как только обнаруживается совпадение, веб-хост прекращает навигацию и посылает брокеру сигнал. Брокер убирает диалоговое окно, очищает любые сохраненные файлы cookie, созданные веб-хостом, из контейнера приложения и возвращает данные протокола обратно приложению.

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

Рис. 3 иллюстрирует модальный диалог WebAuthenticationBroker в приложении-примере Dropbox после того, как веб-хост перешел на начальный URI. Поскольку Dropbox ожидает входа пользователей до появления страницы авторизации, веб-хост перенаправляет процесс навигации на страницу входа в Dropbox.

Страница входа в Dropbox, показываемая в модальном диалоге
Рис. 3. Страница входа в Dropbox, показываемая в модальном диалоге

Как только пользователь вошел в Dropbox, веб-хост переходит к URI авторизации. Это отражено на рис. 4. Из рис. 3 и 4 понятно, что диалог размещается поверх UI моего приложения. UI также остается согласованным безотносительно приложения-источника, вызывающего метод WebAuthenticationBroker::AuthenticateAsync. Поскольку вся пользовательская среда сохраняет согласованность, пользователи могут предоставлять удостоверения, не беспокоясь о приложениях, обрабатывающих эту информацию, и о ее случайной утечке.

Dropbox запрашивает согласие пользователя на авторизацию приложения
Рис. 4. Dropbox запрашивает согласие пользователя на авторизацию приложения

Одна важная вещь, о которой я не упомянул, - необходимость вызова функции WebAuthenticationBroker::AuthenticateAsync из UI-потока. Все веб-запросы в C++ REST SDK выдаются в фоновом потоке, а вывести UI из фонового потока нельзя. Поэтому я использую системный диспетчер и вызываю его функцию-член RunAsync для отображения модального UI (рис. 5).

Рис. 5. Использование системного диспетчера для отображения модального UI

  1. auto action = m_dispatcher->RunAsync(
  2.   Windows::UI::Core::CoreDispatcherPriority::Normal,
  3.   ref new Windows::UI::Core::DispatchedHandler([this]()
  4.   {
  5.     auto beginUri = ref new Uri(ref new String(m_authurl.c_str()));
  6.     task<WebAuthenticationResult^> authTask(WebAuthenticationBroker::
  7.       AuthenticateAsync(WebAuthenticationOptions::None, beginUri));
  8.       authTask.then([this](WebAuthenticationResult^ result)
  9.       {
  10.         String^ statusString;
  11.         switch(result->ResponseStatus)
  12.         {
  13.           case WebAuthenticationStatus::Success:
  14.           {
  15.             auto actionEnable = m_dispatcher->RunAsync(
  16.               Windows::UI::Core::CoreDispatcherPriority::Normal,
  17.               ref new Windows::UI::Core::DispatchedHandler([this]()
  18.               {
  19.                 UploadFileBtn->IsEnabled = true;
  20.               }));
  21.           }
  22.         }
  23.       });
  24. }));

Как только пользователь вошел в Dropbox, веб-хост переходит к URI авторизации.

По окончании процесса авторизации я снова запускаю диспетчер, чтобы сделать доступной кнопку Upload File в основном UI. Эта кнопка остается недоступной, пока пользователи не аутентифицировали и не авторизовали мое приложение для доступа к Dropbox.

Создание цепочки асинхронных веб-запросов

Теперь легко свести все воедино. Во всех функциях, не взаимодействующих с Windows Runtime, я повторно использовал код из моего настольного приложения. Крупных изменений в коде нет, кроме одного: в функции UploadFileToDropboxAsync вместо C++ iostream используется WinRT-объект StorageFile.

При написании приложений Windows Store приходится учитывать некоторые ограничения, с которыми вы должны смириться. Одно из них - необходимость использования WinRT-объектов StorageFile вместо C++-потоков (streams) для чтения и записи данных в файлы. При разработке приложения Windows Store с применением C++ REST SDK все операции, связанные с файлами, ожидают передачи объекта StorageFile, а не C++-объекта потока данных. Внеся это небольшое изменение, я смог повторно использовать весь свой стандартный C++-код, поддерживающий код OAuth-авторизации и Dropbox, в приложении-примере для Windows Store.

Вот как выглядит соответствующий псевдокод (индивидуальные функции мы обсудим после этого псевдокода):

При щелчке кнопки SignIn   Вызов функции oAuthLoginAsync     Затем вызов WebAuthenticationBroker::AuthenticateAsync     Затем делаем доступной кнопку Upload File в UI При щелчке кнопки Upload File    Вызов функции Windows::Storage::Pickers::FileOpenPicker::      PickSingleFileAsync     Затем вызов функции oAuthAcquireTokenAsync     Затем вызов функции UploadFileToDropboxAsync

В обработчике событий кнопки SignInBtnClicked, показанном на рис. 6, я сначала выполняю простую проверку параметров, чтобы удостовериться, что в параметрах ConsumerKey и ConsumerSecret не передаются пустые строки, отправляемые потом в Dropbox для аутентификации. Затем я получаю экземпляр объекта Dispatcher, сопоставленного с текущим потоком CoreWindow, и сохраняю его как переменную-член класса MainPage. Dispatcher отвечает за обработку оконных сообщений и диспетчеризацию событий для приложения. Далее я создаю экземпляр класса OnlineIdAuthenticator. Этот класс содержит вспомогательные функции, которые позволяют мне выводить модальное диалоговое окно приложения и выполнять защищенный рабочий процесс авторизации. Это избавляет от необходимости запуска экземпляра браузера и перевода фокуса ввода с приложения в браузер.

Рис. 6. Функция SignInBtnClicked

  1. void MainPage::SignInBtnClicked(Platform::Object^ sender, 
  2.   RoutedEventArgs^ e)
  3. {
  4.   if ((ConsumerKey->Text == nullptr) // 
  5.     (ConsumerSecret->Text == nullptr))
  6.   {
  7.     using namespace Windows::UI::Popups;
  8.     auto msgDlg = ref new MessageDialog(
  9.       "Please check the input for the Consumer Key and/or Consumer Secret tokens");
  10.     msgDlg->ShowAsync();
  11.   }
  12.   m_dispatcher =
  13.      Windows::UI::Core::CoreWindow::GetForCurrentThread()->Dispatcher;
  14.   m_creds = std::make_shared<AppCredentials>();
  15.   m_authenticator = ref new OnlineIdAuthenticator();
  16.   consumerKey = ConsumerKey->Text->Data();
  17.   consumerSecret = ConsumerSecret->Text->Data();
  18.   ConsumerKey->Text = nullptr;
  19.   ConsumerSecret->Text = nullptr;
  20.   OAuthLoginAsync(m_creds).then([this]
  21.   {          
  22.     m_authurl = DropBoxAuthorizeURI;               
  23.     m_authurl += 
  24.       utility::conversions::to_string_t(this->m_creds->Token());
  25.     m_authurl += L"&oauth_callback=";
  26.     m_authurl += WebAuthenticationBroker::
  27.       GetCurrentApplicationCallbackUri()->AbsoluteUri->Data();
  28.     auto action = m_dispatcher->RunAsync(
  29.       Windows::UI::Core::CoreDispatcherPriority::Normal,
  30.       ref new Windows::UI::Core::DispatchedHandler([this]()
  31.     {
  32.       auto beginUri = ref new Uri(ref new String(m_authurl.c_str()));
  33.       task<WebAuthenticationResult^>authTask(
  34.         WebAuthenticationBroker::AuthenticateAsync(
  35.         WebAuthenticationOptions::None, beginUri));
  36.       authTask.then([this](WebAuthenticationResult^ result)
  37.       {
  38.         String^ statusString;
  39.         switch(result->ResponseStatus)
  40.         {
  41.           case WebAuthenticationStatus::Success:
  42.           {
  43.             auto actionEnable = m_dispatcher->RunAsync(
  44.               Windows::UI::Core::CoreDispatcherPriority::Normal,
  45.               ref new Windows::UI::Core::DispatchedHandler([this]()
  46.               {
  47.                 UploadFileBtn->IsEnabled = true;
  48.               }));
  49.           }
  50.         }
  51.       });
  52.     }));
  53. }

Затем я вызываю функцию OAuthLoginAsync, которая выполняет операцию входа в Dropbox. Как только эта асинхронная функция возвращает управление, я использую функцию RunAsync объекта Dispatcher для маршалинга вызова обратно в UI-поток из фонового потока асинхронной задачи. Функция RunAsync принимает два параметра: значение приоритета и экземпляр DispatchedHandler. Я задаю приоритет как "Normal" и передаю функцию лямбды экземпляру DispatchedHandler. В теле лямбды я вызываю статическую функцию AuthenticateAsync класса WebAuthenticationBroker, которая потом отображает модальный диалог приложения и помогает выполнить защищенную аутентификацию.

При написании приложений Windows Store приходится учитывать некоторые ограничения, с которыми вы должны смириться.

По окончании рабочего процесса диалог удаляется, и функция возвращает либо код успешного завершения, либо обнаруженные ошибки. В моем случае я просто обрабатываю возвращаемый тип WebAuthenticationStatus::Success и снова использую объект диспетчера, чтобы сделать доступной кнопку UploadFile в UI. Поскольку все вызываемые мной функции являются асинхронными, мне нужно задействовать объект диспетчера для маршалинга вызовов в UI-поток, если я хочу обращаться к каким-либо UI-элементам.

Обработчик событий UploadFileBtnClicked показан на рис. 7. В самом обработчике кода не так уж много. Я вызываю функцию FileOpenPicker::PickSingleFileAsync, которая позволяет выбрать один текстовый файл через интерфейс выбора (picker interface). Затем вызываю функцию OAuthAcquireTokenAsync (рис. 8) и при успешном завершении обращаюсь к функции UploadFileToDropBoxAsync (рис. 9).

Рис. 7. Функция UploadFileBtnClicked

  1. void MainPage::UploadFileBtnClicked(  Platform::Object^ sender, 
  2.   RoutedEventArgs^ e)
  3. {
  4.   using namespace Windows::Storage::Pickers;
  5.   using namespace Windows::Storage;
  6.   auto picker = ref new FileOpenPicker();
  7.   picker->SuggestedStartLocation = PickerLocationId::DocumentsLibrary;
  8.   picker->FileTypeFilter->Append(".txt");
  9.   task<StorageFile^> (picker->PickSingleFileAsync())
  10.     .then([this](StorageFile^ selectedFile)
  11.   {
  12.     m_fileToUpload = selectedFile;
  13.     OAuthAcquireTokenAsync(m_creds).then([this](){
  14.       UploadFileToDropBoxAsync(m_creds);
  15.     });
  16.   });         
  17. }

Рис. 8. Функция OAuthAcquireTokenAsync

  1. task<void> MainPage::OAuthAcquireTokenAsync(
  2.   std::shared_ptr<AppCredentials>& creds)
  3. {
  4.   uri url(DropBoxAccessTokenURI);
  5.   std::shared_ptr<OAuth> oAuthObj = std::make_shared<OAuth>();
  6.   auto signatureParams =
  7.     oAuthObj->CreateOAuthSignedParameters(url.to_string(),
  8.     L"GET",
  9.     NULL,
  10.     consumerKey,
  11.     consumerSecret,
  12.     creds->Token(),
  13.     creds->TokenSecret()
  14.     );
  15.   std::wstring sb = oAuthObj->OAuthBuildSignedHeaders(url);
  16.   http_client client(sb);   
  17.   // Выдаем запрос и асинхронно обрабатываем ответ
  18.   return client.request(methods::GET)
  19.     .then([&creds](http_response response)
  20.   {
  21.     if(response.status_code() != status_codes::OK)
  22.     {
  23.       auto stream = response.body();                    
  24.       container_buffer<std::string> inStringBuffer;
  25.       return stream.read_to_end(inStringBuffer)
  26.         .then([inStringBuffer](pplx::task<size_t> previousTask)
  27.       {
  28.         UNREFERENCED_PARAMETER(previousTask);
  29.         const std::string &text = inStringBuffer.collection();
  30.         // Преобразуем текст ответа в широкосимвольную строку
  31.         std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>,
  32.            wchar_t> utf16conv;
  33.         std::wostringstream ss;
  34.         ss << utf16conv.from_bytes(text.c_str()) << std::endl;
  35.         OutputDebugString(ss.str().data());
  36.         // Обработка ошибок                  
  37.         return pplx::task_from_result();
  38.       });
  39.     }
  40.     // Здесь выполняем операции, читая из потока ответа
  41.     istream bodyStream = response.body();
  42.     container_buffer<std::string> inStringBuffer;
  43.     return bodyStream.read_to_end(inStringBuffer)
  44.       .then([inStringBuffer, &creds](pplx::task<size_t> previousTask)
  45.     {
  46.       UNREFERENCED_PARAMETER(previousTask);
  47.       const std::string &text = inStringBuffer.collection();
  48.       // Преобразуем текст ответа в широкосимвольную строку
  49.       std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, 
  50.         wchar_t> utf16conv;
  51.       std::wostringstream ss;
  52.       std::vector<std::wstring> parts;
  53.       ss << utf16conv.from_bytes(text.c_str()) << std::endl;
  54.       Split(ss.str(), parts, '&', false);
  55.       unsigned pos = parts[1].find('=');
  56.       std::wstring token = parts[1].substr(pos + 1, 16);
  57.       pos = parts[0].find('=');
  58.       std::wstring tokenSecret = parts[0].substr(pos + 1);
  59.       creds->SetToken(token);
  60.       creds->SetTokenSecret(tokenSecret);
  61.     });
  62.   });
  63. }

Рис. 9. Функция UploadFileToDropBoxAsync

  1. task<void> MainPage::UploadFileToDropBoxAsync(
  2.   std::shared_ptr<AppCredentials>& creds)
  3. {
  4.   using concurrency::streams::file_stream;
  5.   using concurrency::streams::basic_istream;
  6.   uri url(DropBoxFileUploadURI);
  7.   std::shared_ptr<oAuth> oAuthObj = std::make_shared<oAuth>();
  8.   auto signatureParams =
  9.     oAuthObj->CreateOAuthSignedParameters(url.to_string(),
  10.     L"PUT",
  11.     NULL,
  12.     consumerKey,
  13.     consumerSecret,
  14.     creds->Token(),
  15.     creds->TokenSecret()
  16.   );          
  17.   std::wstring sb = oAuthObj->OAuthBuildSignedHeaders(url);
  18.   return file_stream<unsigned char>::open_istream(this->m_fileToUpload)
  19.     .then([this, sb, url](pplx::task<basic_istream<unsigned char>> previousTask)
  20.   {
  21.     try
  22.     {
  23.       auto fileStream = previousTask.get();
  24.       // Получаем длину контента,
  25.      // присвоенного свойству Content-Length
  26.       fileStream.seek(0, std::ios::end);
  27.       auto length = static_cast<size_t>(fileStream.tell());
  28.       fileStream.seek(0, 0);
  29.       // Выдаем HTTP-запрос с файловым потоком в качестве тела
  30.       http_request req;
  31.       http_client client(sb);
  32.       req.set_body(fileStream, length);
  33.       req.set_method(methods::PUT);
  34.       return client.request(req)
  35.         .then([this, fileStream](pplx::task<http_response> previousTask)
  36.       {
  37.         fileStream.close();
  38.         std::wostringstream ss;
  39.         try
  40.         {
  41.           auto response = previousTask.get();
  42.           auto body = response.body();                  
  43.           // Протоколируем код успешного ответа
  44.           ss << L"Server returned status code "
  45.           << response.status_code() << L"."
  46.           << std::endl;
  47.           OutputDebugString(ss.str().data());
  48.           if (response.status_code() == web::http::status_codes::OK)
  49.           {
  50.             auto action = m_dispatcher->RunAsync(
  51.               Windows::UI::Core::CoreDispatcherPriority::Normal,
  52.               ref new Windows::UI::Core::DispatchedHandler([this]()
  53.               {
  54.                 using namespace Windows::UI::Popups;
  55.                 auto msgDlg = ref new MessageDialog(
  56.                   "File uploaded successfully to Dropbox");
  57.                 msgDlg->ShowAsync();
  58.               }));
  59.           }
  60.         }
  61.         catch (const http_exception& e)
  62.         {
  63.           ss << e.what() << std::endl;
  64.           OutputDebugString(ss.str().data());
  65.         }
  66.       });           
  67.     }                         
  68.     catch (const std::system_error& e)
  69.     {
  70.       // Здесь протоколируем любые ошибки
  71.       // и возвращаем пустую задачу
  72.       std::wostringstream ss;
  73.       ss << e.what() << std::endl;
  74.       OutputDebugString(ss.str().data());
  75.       return pplx::task_from_result();
  76.     }
  77.   });
  78. }

Функция OAuthAcquireTokenAsync получает маркер, сопоставленный с учетной записью Dropbox. Сначала я формирую необходимую строку доступа (access string) и заголовки HTTP-запроса и вызываю сервис Dropbox для проверки удостоверений. Этот HTTP-запрос имеет тип GET, а ответ возвращается как поток символов. Я разбираю этот поток для получения самого маркера и секрета, которые потом сохраняются в экземпляре класса AppCredentials.

Успешно получив маркер и его секрет от Dropbox, я использую их для загрузки файла в Dropbox. Как и в случае любой конечной точки веб-доступа к Dropbox, сначала формируется строка параметров и HTTP-заголовки. Затем вызывается конечная точка сервиса Dropbox, сопоставленная с загрузкой файлов. Этот HTTP-запрос имеет тип PUT, поскольку я пытаюсь поместить контент в сервис. Перед этим мне также нужно сообщить Dropbox о размере контента. Это указывается установкой значения свойства content_length в методе HTTP_request::set_body равным размеру загружаемого файла. После успешного возврата PUT-метода с помощью объекта диспетчера я вывожу пользователю сообщение об успешном завершении операции.

На очереди Linux

Интеграция C++ REST SDK в приложения Windows 8 (как Windows Store, так и настольные) проста и прямолинейна. Добавьте преимущества написания кода, который может быть общим между двумя платформами, применение идиом программирования на современном C++ и тот факт, что данный код является портируемым между приложениями как Windows, так и других ОС, - и приз ваш. Вы можете больше не беспокоиться о специфичных для платформ тонкостях, относящихся к сетевым API, и вместо этого уделять больше времени продумыванию функциональности, которую должно поддерживать ваше приложение. В этом простом примере я задействовал C++ REST SDK для аутентификации пользователя в Dropbox и последующей загрузки файла в облако Dropbox. Подробнее о Dropbox REST API см. документацию по ссылке bit.ly/10OdTD0. В следующей статье я покажу, как выполнять те же задачи из Linux-клиента.

Сридхар Подури (Sridhar Poduri) - менеджер программ в группе Windows в Microsoft. Страстный поклонник C++ и автор книги "Modern C++ and Windows Store Apps" (Sridhar Poduri, 2013), регулярно пишет о C++ и Windows Runtime в своем блоге sridharpoduri.com.

Выражаю благодарность за рецензирование статьи экспертам Microsoft Никласу Густаффсону (Niklas Gustaffson), Сана Митани (Sana Mithani) и Огги Шобахичу (Oggy Sobajic).



 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 17.01.2014 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
Microsoft 365 Business Standard (corporate)
Microsoft 365 Apps for business (corporate)
Microsoft Windows Professional 10, Электронный ключ
Microsoft 365 Business Basic (corporate)
Microsoft Office для дома и учебы 2019 (лицензия ESD)
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Безопасность компьютерных сетей и защита информации
Новости ITShop.ru - ПО, книги, документация, курсы обучения
Программирование на Microsoft Access
CASE-технологии
OS Linux для начинающих. Новости + статьи + обзоры + ссылки
Компьютерные книги. Рецензии и отзывы
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100