Сложные приёмы разработки приложений для Windows Phone 8

Работа с API веб-сервисов

Показывать лекцию целиком

Цель работы: освоить технологию работы с API веб-сервисов

Предварительная подготовка и исследование API

Если разработчик хочет создать приложение, взаимодействующее с неким веб-сервисом, сначала следует изучить интерфейс программирования (API), который реализован на данном сервисе и позволяет организовывать взаимодействие с ним приложений. Подавляющее большинство сервисов поддерживают те или иные API, иногда речь идёт о нескольких интерфейсах, построенных с использованием различных технологий. На начальном этапе подготовки к разработке следует выяснить особенности их использования. Обычно владельцы сервисов положительно относятся к разработчикам приложений, так как такие приложения, фактически, расширяют аудиторию сервиса, расширяют его присутствие на различных платформах. В данном случае речь идёт о платформе Windows Phone.

Поэтому на веб-сайтах сервисов обычно имеется документация по их API, которая содержит много полезной информации. Для того, чтобы найти такие разделы, обычно нужно приложить некоторые усилия для их поисков, например, выполнить поисковый запрос по названию сервиса с добавлением ключевых слов "API" или "Development". Например, поиск по ключевым словам "twitter API" позволяет найти ссылку на портал разработчиков Twitter: https://dev.twitter.com/, рис. 31.1. где в разделе Documentation (Документация) можно найти интересующие нас материалы. Изучение справочного раздела сервиса Twitter позволяет узнать о том, что этот сервис поддерживает REST-API, для авторизации в сервисе используется протокол OAuth.

(рис 31.1) Начальная страница портала разработчиков Twitter

Перед началом работы приложения и в Twitter, и во многих других сервисах, сначала следует зарегистрировать приложение, в частности, такая регистрация может быть автоматической, она может подразумевать модерацию, требовать ввода каких-либо сведений о приложении. Регистрация приложения в сервисах преследует цель идентификации приложения. В данном случае процедура регистрации выполняется в разделе Manage create your application (Управление приложением и создание приложений), для запуска процесса создания приложения служит кнопка Create a new application (Создать новое приложение). После успешного завершения регистрации и получения данных, которые приложение будет использовать для авторизации в сервисе (в частности, это - Consumer key и Consumer secret), можно приступать к изучению API.

Не все вызовы веб-сервисов требуют авторизации пользователя. Например, к некоторым механизмам Twitter можно обращаться напрямую, без авторизации.

Для того, чтобы приступить к созданию приложения для Facebook, нужно начать со страницы https://developers.facebook.com. Зарегистрировавшись в этой службе и создав новое приложение, вы получите данные, необходимые для дальнейшей работы, в частности, это AppID/API key и App Secret.

У сервиса Вконтакте так же есть страница документации для разработчиков, http://vk.com/developers.php#devstep1. Здесь используется та же процедура регистрации приложения.

Интерфейс для программного доступа к службе имеется и у проекта Wikipedia, http://www.mediawiki.org/wiki/API:Main_page/ru.

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

Рассмотрим несколько приложений, реализующих доступ к веб-службам.

Twitter

Рассмотрим приложение для выполнения поиска в Twitter, "Поиск в Twitter, пример использования бесконечной прокрутки в LongListSelector" (этот пример можно скачать здесь: http://code.msdn.microsoft.com/TwitterSearch-Windows-b7fc4e5e). Его особенность заключается в том, что оно взаимодействует с сервисом Twitter методами, не требующими авторизации, выполняя запросы к общедоступным механизмам службы. В частности, интересующая нас функциональность данного приложения (рис. 31.2.) реализована в файле TwitterViewModel.cs.

(рис 31.2) Приложение для поиска в Twitter

В целом, приложение реализовано с помощью уже известного вам MVVM-подхода, в файле TwitterModel.cs определена структура данных, которая используется при формировании отдельного элемента, полученного от сервиса, TwitterViewModel (Листинг 16.1) – это модель представления, с помощью механизма привязки данных связанная с MainPage.xaml, где, записи выводятся в списке, с реализацией загрузки дополнительного содержимого при достижении последней записи, присутствующей в настоящий момент в списке

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.ServiceModel.Syndication;
using System.Windows;
using System.Xml;
using TwitterSample.Model;

namespace TwitterSample.ViewModels
{
    public class TwitterViewModel:INotifyPropertyChanged
    {
        const string SEARCH_URI = "http://search.twitter.com/search.atom?q={0}page={1}";

        private bool _isLoading = false;

        public bool IsLoading
        {
            get
            {
                return _isLoading;
            }
            set
            {
                _isLoading = value;
                NotifyPropertyChanged("IsLoading");

            }
        }       

        public TwitterViewModel()
        {
             this.TwitterCollection = new ObservableCollection<TwitterSearchResult>();
             this.IsLoading = false;
             
        }

        public ObservableCollection<TwitterSearchResult> TwitterCollection
        {
            get;
            private set;
        }

        public void LoadPage(string searchTerm, int pageNumber)
        {
            if (pageNumber == 1) this.TwitterCollection.Clear();

            IsLoading = true;
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri
(String.Format(SEARCH_URI, searchTerm, pageNumber)));
       request.BeginGetResponse(new AsyncCallback(ReadCallback), request); 
        }        

        private void ReadCallback(IAsyncResult asynchronousResult)
        {
            try
            {
                HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
                HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
                using (StreamReader reader = new StreamReader(response.GetResponseStream()))
                {
                    //только для демонстрационных целей, не следует отправлять приложение 
на сертификацию с этой строкой.
                    System.Threading.Thread.Sleep(700);

                    NameTable nt = new NameTable();

                    XmlNamespaceManager nsmgr = new XmlNamespaceManager(nt);
                    nsmgr.AddNamespace("georss", "http://www.w3.org/2001/XMLSchema-instance");
                    XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None);
                    XmlReaderSettings xset = new XmlReaderSettings();
                    xset.ConformanceLevel = ConformanceLevel.Fragment;


                    XmlReader rdr = XmlReader.Create(reader, xset, context);

                    SyndicationFeed feed = SyndicationFeed.Load(rdr);                    

                    Deployment.Current.Dispatcher.BeginInvoke(() =>
                    {

                        foreach (var item in feed.Items)
                        {

                            this.TwitterCollection.Add(new TwitterSearchResult()
                            {
                                Author = item.Authors[0].Name,
                                ID = GetTweetId(item.Id),
                                Tweet = item.Title.Text,
                                PublishDate = item.PublishDate.DateTime.ToLocalTime(),
                                AvatarUrl = item.Links[1].Uri.AbsoluteUri
                            });

                        }
                        IsLoading = false;
                    });

                }
            }
            catch (Exception e)
            {
                Deployment.Current.Dispatcher.BeginInvoke(() =>
                   {
                       MessageBox.Show("Network error occured " + e.Message);
                   });
            }
        }

        private string GetTweetId(string twitterId)
        {
            string[] parts = twitterId.Split(":".ToCharArray());

            return parts[2].ToString();
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

Для выполнения запросов к службе используется URI следующего вида: http://search.twitter.com/search.atom?q={0}page={1} (подробности о поиске в Twitter можно найти здесь: https://dev.twitter.com/docs/api/1.1/get/search/tweets, нужно учесть, что API как этого сервиса, так и других периодически обновляется, в частности, в API Twitter наблюдается переход от формата ATOM, который используется в данном примере для поиска, к формату JSON, в частности, для вызова операции поиска будет применятся ссылка следующего вида: https://api.twitter.com/1.1/search/tweets.json, дополнительные подробности можно найти здесь: https://dev.twitter.com/docs/using-search).

Вышеозначенная ссылка для доступа к службе используется при построении запроса для HttpWebRequest, который находится в методе LoadPage(), вызываемом из кода страницы MainPage.xaml. Разбор результатов запроса осуществляется в методе ReadCallBack().

Facebook

Пример, демонстрирующий работу с сервисом Facebook и дополнительные материалы можно найти здесь: https://github.com/facebook-csharp-sdk/facebook-windows-phone-sample. Фактически, здесь речь идёт о примере использования библиотеки Facebook C# SDK v6 в приложениях для Windows Phone.

Пример (Рис. 16.3) демонстрирует применение библиотеки в Windows Phone 7, преобразование проекта к версии платформы Windows Phone 8 подтверждает работоспособность используемых механизмов в Windows Phone 8. Библиотеки, подобные рассматриваемой здесь, периодически обновляются, поэтому вполне можно ожидать появления новой версии библиотеки, которая предназначена для Windows Phone 8.

(рис 31.3) Приложение, демонстрирующее работу с Facebook

Для успешного запуска приложения нужно заранее зарегистрировать приложение в сервисе Facebook и получить идентификатор приложения (App ID/API Key). Указание этого идентификатора в соответствующем месте приложения (в файле кода к странице FacebookLoginPage.xaml.cs, в строковой константе AppId), во-первых, приводит к возможности успешно запустить приложение, во-вторых, приводит к тому, что Facebook распознаёт это приложение как то, которое вы зарегистрировали и идентификатор которого указали. Этот идентификатор стоит держать в секрете, так как, хотя разработчик и может контролировать зарегистрированное приложение, знание его третьими лицами позволит им создать приложение, действующее от имени приложения разработчика.

В приложении реализована следующая схема работы. Страница MainPage.xaml содержит кнопку Login To Facebook, нажатие на которую приводит к открытию страницы FacebookLoginPage.xaml (Листинг 16.2). Не забудьте, что, для работы приложения нужно заполнить поле AppId, введя в него данные приложения, зарегистрированного на Facebook (https://developers.facebook.com).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Facebook;

namespace facebook_windows_phone_sample.Pages
{
    public partial class FacebookLoginPage : PhoneApplicationPage
    {
        private const string AppId = "";

        /// <summary>
        /// Расширенные разрешения – это список полномочий, разделенных запятой и запрашиваемых у пользователя
        /// </summary>
        /// <remarks>
        /// Список доступных расширенных разрешений можно найти по данной ссылке 
        /// https://developers.facebook.com/docs/reference/api/permissions/
        /// </remarks>
        private const string ExtendedPermissions = "user_about_me,read_stream,publish_stream";

        private readonly FacebookClient _fb = new FacebookClient();

        public FacebookLoginPage()
        {
            InitializeComponent();
        }

        private void webBrowser1_Loaded(object sender, RoutedEventArgs e)
        {
            var loginUrl = GetFacebookLoginUrl(AppId, ExtendedPermissions);
            webBrowser1.Navigate(loginUrl);
        }

        private Uri GetFacebookLoginUrl(string appId, string extendedPermissions)
        {
            var parameters = new Dictionary<string, object>();
            parameters["client_id"] = appId;
            parameters["redirect_uri"] = "https://www.facebook.com/connect/login_success.html";
            parameters["response_type"] = "token";
            parameters["display"] = "touch";

            // добавляем 'scope' только если имеется extendedPermissions.
            if (!string.IsNullOrEmpty(extendedPermissions))
            {
                // Список разрешений, разделённых запятой
                parameters["scope"] = extendedPermissions;
            }

            return _fb.GetLoginUrl(parameters);
        }

        private void webBrowser1_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
        {
            FacebookOAuthResult oauthResult;
            if (!_fb.TryParseOAuthCallbackUrl(e.Uri, out oauthResult))
            {
                return;
            }

            if (oauthResult.IsSuccess)
            {
                var accessToken = oauthResult.AccessToken;
                LoginSucceded(accessToken);
            }
            else
            {
                // Отменено пользователем
                MessageBox.Show(oauthResult.ErrorDescription);
            }
        }

        private void LoginSucceded(string accessToken)
        {
            var fb = new FacebookClient(accessToken);

            fb.GetCompleted += (o, e) =>
            {
                if (e.Error != null)
                {
                    Dispatcher.BeginInvoke(() => MessageBox.Show(e.Error.Message));
                    return;
                }

                var result = (IDictionary<string, object>)e.GetResultData();
                var id = (string)result["id"];

                var url = string.Format("/Pages/FacebookInfoPage.xaml?access_token={0}id={1}", accessToken, id);

                Dispatcher.BeginInvoke(() => NavigationService.Navigate(new Uri(url, UriKind.Relative)));
            };

            fb.GetAsync("me?fields=id");
        }
    }
}

На данной странице расположен элемент управления WebBrowser. Фактически, авторизация пользователя в сервисе происходит с использованием веб-интерфейса сервиса. Здесь пользователь вводит учетные данные, даёт, если считает нужным, разрешения приложению на выполнение некоторых действий, после успешной авторизации приложение получает некоторые сведения, в частности, маркер доступа (access token) и идентификатор пользователя (user id). Здесь же начинается применение механизмов библиотеки Facebook, в частности, используется класс FacebookClient.

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

Выводы

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

Задание

Подумайте, какие выгоды приложение, разработкой которого вы занимаетесь, может извлечь из работы с веб-сервисами, предоставляющими программный доступ к своим возможностям. Существует огромное количество таких сервисов, если известные вам сервисы не представляется возможным использовать в приложении, поработайте со списком веб-служб по этому адресу: http://www.programmableweb.com/apis. Здесь сервисы разделены по категориям, присутствуют краткие описания их API. Выберите как минимум 5 служб, которые могли бы представлять интерес для использования в вашем приложении и подготовьте обзорное сообщение по ним. Вы можете выбрать и большее количество служб – возможно, кому-нибудь из группы пригодится один из сервисов, рассмотренных вами.

Дополнительные материалы

К данной лабораторной работе подготовлено видеоприложение.

Вернуться к учебному плану