Эта статья посвящена масштабируемости и взаимодействию — двум характеристикам, необходимым в архитектурах, которые должны поддерживать множество современных мобильных платформ, популярных в настоящее время, с потенциальной аудиторией в миллионы пользователей. В табл. 1 показано, с каким разнообразием приходится иметь дело современным разработчикам. Предоставление веб-сервисов для мобильных устройств — устрашающе сложная задача, требующая применения совершенно разных инструментов, языков и сред программирования. Помимо этого разнообразия, нужно учитывать потребность в эластичном масштабировании — в плане доступных веб-сервисов и объемов данных, которые могут исчисляться в терабайтах.
Табл. 1. Набор разных мобильных технологий — трудная задача для разработчиков
Тип приложения | Платформа | Среда разработки | Язык |
Мобильное | Windows Phone | Visual Studio | C# |
Мобильное | Android | Eclipse | Java |
Мобильное | iOS | Xcode | Objective-C |
Веб-сервер в облаке | Windows Azure | Visual Studio | C# |
Разработчикам нужно масштабировать свои веб-приложения в двух областях. Первая область — вычисления, что, по сути, сводится к количеству экземпляров веб-сервиса, которое может быть доступно от провайдера хостинга в ответ на запросы с мобильных устройств. Вторая область — масштабируемые данные. Некоторые облачные платформы предлагают масштабирование данных через выделенные сервисы хранилищ. Это позволяет разработчикам передавать терабайты данных миллионам мобильных пользователей и безо всяких усилий распределять их по множеству серверов, что обеспечивает высокую производительность, поддержку избыточности и пропускные возможности для петабайтов данных.
Для поддержки взаимодействия с максимально разнообразными устройствами, крайне важен подход, рассчитанный на такое взаимодействие. Необходимо тщательно продумывать все — от форматов данных до сетевых протоколов. Решение должно сводить к минимуму кодирование со стороны потребителей сервисов и как можно шире использовать открытые стандарты.
В этой статье для решения задач взаимодействия и эластичного масштабирования мы используем веб-сервисы RESTful, размещенные в Windows Azure — облачной платформе Microsoft.
Эталонная архитектура веб-сервисов на основе RESTful приведена на рис. 2. RESTful-архитектуры обладают широкими возможностями во взаимодействии, так как они разработаны вместе с HTTP/1.x и обеспечивают согласованное взаимодействие между огромным массивом клиентских устройств. Архитектура, альтернативная REST, — SOAP. Мы предпочли не использовать SOAP, поскольку с ней связаны дополнительные сложности и она требует передачи несколько больших объемов вспомогательных данных.
Рис. 1. Решение на основе открытых стандартов
Windows Azure упрощает увеличение и уменьшение масштаба по требованию. Простым изменением одного числа — Instance Count в Windows Azure Portal или через API управления — вы можете почти без усилий масштабировать веб-сервисы RESTful под любой уровень запросов.
В нашей реализации в качестве формата данных используется JSON (а не XML), потому что он компактен и широко поддерживается. Недостаток XML для наших целей заключается в большем объеме вспомогательных данных.
Хотя хостинг в облаке для веб-сервисов RESTful предлагают многие провайдеры, у Windows Azure есть некоторые преимущества. Для начала вы можете выбирать между шестью высокоавтоматизированными информационными центрами в Азии, Европе и Северной Америке, в том числе с поддержкой 24 Content Delivery Networks (CDN), что обеспечивает пользователям соединения с низкими задержками и возможностью перенаправления в ближайшие к ним информационные центры.
Windows Azure предлагает множество вариантов хранения и вычислений в дополнение к мощному инструментарию для разработки. Вам доступны разнообразные механизмы хранения — от Binary Large Objects (BLOB) до реляционных хранилищ. Windows Azure также предоставляет системы управления идентификациями, безопасного обмена сообщениями и средства для создания гибридных подключений (облако/локальное предприятие).
Приступаем к работе
В оставшейся части статьи мы поделим архитектуру и реализацию на четыре части:
1. Создание учетной записи с помощью Windows Azure Portal.
2. Создание Windows Azure Cloud Project и написание кода для определения веб-сервиса на основе RESTful.
3. Развертывание облачного проекта с использованием учетной записи в Windows Azure Portal.
4. Создание мобильных приложений для Windows Phone, Android и iOS (iPhone/iPad).
Давайте пройдем эти этапы вместе. Первый шаг мы должны сделать в Windows Azure Portal, доступный по ссылке windows.azure.com, если у вас есть подписка. (За более подробной информацией обращайтесь на azure.com.)
Часть 1: предоставление веб-сервиса в Windows Azure Portal
Два основных варианта в Windows Azure Portal: New Hosted Service и New Storage Account.
На рис. 2 показан рабочий процесс предоставления размещенного сервиса (hosted service). Этот процесс приведет к получению URL, представляющего конечную точку в каком-либо информационном центре Microsoft, где будет развернут веб-сервис RESTful. Этот URL понадобится разработчикам приложений Windows Phone, Android и iOS для взаимодействия с данным сервисом.
Рис. 2. Предоставление веб-сервиса RESTful в Windows Azure
Этот рабочий процесс достаточно прямолинеен:
1. Войдите в Windows Azure Portal.
2. Выберите New Hosted Service. Укажите имя учетной записи, URL и регион (местонахождение информационного центра).
3. Сохраните URL, генерируемый Windows Azure Portal; он потребуется позже (вместе с именем учетной записи), когда вы будете создавать веб-сервис RESTful и мобильные клиенты. Имя учетной записи будет использоваться и в третьей части.
Заметьте: в примере в этой статье применяется имя учетной записи fastmotorcycleservice, а URL представляет собой «http://fastmotorcycleservice.cloudapp.net».
Вторая задача в Windows Azure Portal — создание Storage Account (учетной записи хранилища). Этот процесс проиллюстрирован на рис. 3, в том числе приведены имя и месторасположение таблиц Windows Azure. И вновь у вас выбор из шести информационных центров. Для уменьшения расходов и увеличения производительности имеет смысл размещать веб-сервис и данные в одном и том же информационном центре.
Рис. 3. Предоставление учетной записи Windows Azure Storage
Этот рабочий процесс аналогичен ранее рассмотренному для размещения сервиса.
1. Войдите в Windows Azure Portal.
2. Создайте новую учетную запись хранилища и введите ее имя и регион.
3. Сохраните ключ доступа, который генерируется и предоставляется Windows Azure Portal, а также имя учетной записи; они потребуются при создании веб-сервиса RESTful.
С первой частью мы закончили, и необходимая информация Windows Azure Portal может использоваться для написания веб-сервиса RESTful, а также приложений Windows Phone, Android и iOS.
Часть 2: создание веб-сервиса RESTful, размещаемого в Windows Azure
Создать веб-сервис RESTful в Visual Studio довольно легко. Откройте Visual Studio как администратор из Start | All Programs | Microsoft Visual Studio 2010, щелкните правой кнопкой мыши ярлык Microsoft Visual Studio 2010 и выберите команду Run as administrator. В меню File укажите New | Project.
В диалоге New Project выберите предпочитаемый язык и раскройте список Installed Templates, в котором укажите Cloud. Выберите шаблон Windows Azure Project, присвойте проекту имя FastMotorcycleProject и задайте любое удобное вам месторасположение этого проекта.
Видеоролик, подробно демонстрирующий все эти операции, можно найти по ссылке bit.ly/VideoAzureRestfulService.
Окно Solution Explorer будет выглядеть как на рис. 4.
Рис. 4. Создание нового проекта для Windows Azure
В табл. 2 перечислены некоторые базовые операции, не рассматриваемые в этой статье (но показанные в упомянутом выше видеоролике).
Табл. 2. Базовые операции, не рассматриваемые в этой статье
Операция, показанная в видеоролике | Примечания |
Добавление веб-роли ASP.NET | Эта роль будет использоваться для размещения веб-сервиса RESTful |
Добавление DataConnectionString | Эта строка будет включать имя учетной записи и ключ доступа |
Добавление базового стартового кода для инициализации данных | Код в global.asax.cs для чтения DataConnectionString |
Эти операции одинаковые почти для всех проектов Windows Azure. Например, использование веб-роли для размещения веб-сервисов RESTful является стандартной практикой. DataConnectionString нужна для доступа к учетной записи хранилища, определенной ранее в Windows Azure Portal. В проекте Visual Studio требуется стартовый код для чтения имен учетных записей и ключей доступа из конфигурационных файлов для последующего использования учетных записей хранилища.
Закончив с подготовительными операциями, вы можете добавить веб-сервис RESTful с помощью шаблона WCF Service в Visual Studio.
Чтобы добавить веб-сервис, щелкните правой кнопкой мыши папку FastMotorcycleProject_WebRole, выберите Add | New Item и присвойте классу имя FastMotorcycleService.
После этого будет сгенерирован файл FastMotorcycleService.svc.cs. Замените весь код класса кодом, показанным на рис. 5.
Рис. 5. FastMotorcycleListService.svc.cs
[ServiceContract] public class FastMotorcycleListService { private FastMotorcycleListDataProvider _data; public FastMotorcycleListService() { _data = new FastMotorcycleListDataProvider(); } [OperationContract] [WebGet(UriTemplate = "/list/{owner}", ResponseFormat = WebMessageFormat.Json)] public List<string> GetItems(string owner) { return _data.GetItems(owner); } [OperationContract] [WebInvoke(UriTemplate = "/list/{owner}", Method = "POST", RequestFormat = WebMessageFormat.Json)] public void AddItem(string owner, string item) { _data.AddItem(owner, item); } [OperationContract] [WebInvoke(UriTemplate = "/list/{owner}/{item}", Method = "DELETE")] public void DeleteItem(string owner, string item) { _data.DeleteItem(owner, item); } }
Ключ к правильному выполнению этой работы — знание того, как сопоставляются различные URI и команды RESTful-методам. Для этого в код на рис. 5 нужно добавить атрибуты WebGet и WebInvoke.
Эти атрибуты сообщают инфраструктуре, что данный метод должен отвечать на HTTP-запросы GET. WebInvoke по умолчанию сопоставляется с HTTP POST. Кроме того, по умолчанию URI определяется именем метода (добавляемый к базовому URI конечной точки). (Некоторые эксперты и блюстители чистоты REST могут возразить, что имена наших методов должны быть не глаголами, а существительными.)
WCF-модель программирования REST, показанная на рис. 6, допускает настройку URI для каждого метода с помощью шаблонов, которые можно задать через свойство UriTemplate в атрибутах WebInvoke и WebGet. Эта модель поясняется в следующем списке, причем его нумерация соответствует используемой на рис. 6.
- Мобильное приложение отправляет по стандартному HTTP сообщение-запрос, которое включает HTTP-команду и URL.
- Веб-сервис RESTful перехватывает сообщение-запрос от мобильного приложения (запрос данных) и вызывает GetItems, передавая «Bruno» в качестве параметра. GetItems запрашивает данные через LINQ-запрос, используя «Bruno» как часть блока where.
- Из Windows Azure Table Service возвращаются только записи, в которых PartitionKey равен «Bruno».
- Данные автоматически преобразуются в формат JSON и возвращаются мобильному устройству.
- Данные становятся доступными мобильному приложению. Эти данные применяются для заполнения ListBox и его вывода пользователю мобильного приложения.
Рис. 6. Рабочий процесс для мобильного приложения, запрашивающего RESTful-данные
Увеличить
Далее мы обсудим три вспомогательных класса, необходимых для взаимодействия с Windows Azure Table Service. FastMotorcycleListDataProvider, FastMotorcycleListItem и FastMotorcycleList — это классы, которые абстрагируют хранилище и API, специфичный для Windows Azure Table, от кода на рис. 7, позволяя приложению выполнять CRUD-операции (Create, Read, Update, Delete) с помощью Windows Azure Table Service.
Рис. 7. Классы FastMotorcycleListDataProvider, FastMotorcycleListItem и FastMotorcycleList
public class FastMotorcycleListDataProvider { private FastMotorcycleList _list; public FastMotorcycleListDataProvider() { string configValue = RoleEnvironment. GetConfigurationSettingValue("DataConnectionString"); var account = CloudStorageAccount.Parse(configValue); _list = new FastMotorcycleList( account.TableEndpoint.ToString(),account.Credentials); } public List<string> GetItems(string owner) { var results = from entity in _list.Items where entity.PartitionKey == owner select entity; var list = new List<string>(); foreach (var item in results) { list.Add(item.RowKey); } return list; } public void AddItem(string owner, string item) { _list.AddObject("FastBikes", new FastMotorcycleListItem(owner, item)); _list.SaveChanges(); } public void DeleteItem(string owner, string item) { var entity = (from i in _list.Items where i.PartitionKey == owner && i.RowKey == item select i).Single(); _list.DeleteObject(entity); _list.SaveChanges(); } } public class FastMotorcycleListItem : TableServiceEntity { public FastMotorcycleListItem() { } public FastMotorcycleListItem(string partitionKey, string rowKey) : base(partitionKey, rowKey) { } } public class FastMotorcycleList : TableServiceContext { public FastMotorcycleList(string baseAddress, StorageCredentials storageCredentials) : base(baseAddress, storageCredentials) { } public DataServiceQuery<FastMotorcycleListItem> Items { get { return this.CreateQuery<FastMotorcycleListItem>( "FastBikes"); } } }
В Visual Studio добавьте новый модуль классов с именем FastMotorcycleListDataProvider.cs. Замените в нем код на то, что показано на рис. 7.
Часть 3: развертывание веб-сервиса RESTful
Эта одна из областей, где особенно ярко проявляются преимущества Windows Azure. Развернуть 100 экземпляров веб-сервиса RESTful столь же легко, как и один. Для этого выполните следующее.
- В Visual Studio щелкните правой кнопкой мыши FastMotorcycleProject и выберите Package.
- Вернитесь в браузер с открытым в нем порталом и выберите «Hosted Services, Storage Accounts & CDN».
- В верхней секции выберите Hosted Services.
- В средней секции укажите Hosted Service, который вы создали ранее.
- Щелкните правой кнопкой мыши и выберите New Production Deployment, а затем загрузите файлы (FastMotorcycleProject.cspkg и ServiceConfiguration.Cloud.cscfg), которые были сгенерированы на первой стадии.
Часть 4: использование веб-сервисов RESTful из мобильных приложений
Теперь мы обсудим использование веб-сервисов RESTful из различных мобильных приложений. В этом разделе основное внимание уделяется поддержке взаимодействия с различными мобильными платформами.
JSONKit (github.com/johnezang/JSONKit) упрощает взаимодействие с веб-сервисом RESTful для устройств под управлением iOS. С помощью нескольких строк кода можно вызвать веб-сервис RESTful, скачать данные в формате JSON, преобразовать их в более удобный формат и связать преобразованные данные с элементом управления TableView, который используется в приложениях iPhone или iPad (рис. 8).
Рис. 8. Код на Objective-C, разбирающий JSON-данные
// Передается в веб-сервис RESTful NSString *username = @"Bruno"; NSString *serviceUri = "http://your_hosted_service_name.cloudapp.net/"+ "FastMotorcycleListService.svc/list/"; // Формируем URI сервиса (будет указывать // на наш веб-сервис RESTful) NSString *url = [NSString stringWithFormat:@"%@%@", serviceUri, username]; // Получаем данные в виде JSON-массива NSData *json = [NSData dataWithContentsOfURL: [NSURL URLWithString:url]]; // Преобразуем JSON-массив в NSArray, что упрощает // заполнение элемента управления TableView NSArray *itemArray = [json objectFromJSONData]; // Назначаем массив элементу TableView; // fastbikes – это имя нашего элемента управления TableView self.fastbikes = [[NSMutableArray alloc] initWithArray:itemArray];
В разработке для Android применяется язык программирования Java, который существует уже довольно давно и способен оперировать JSON-данными. Пример показан на рис. 9. В Windows Phone SDK включена поддержка вызова веб-сервисов RESTful и возможность обработки данных в формате JSON. Этот SDK облегчает обработку JSON-данных с помощью DataContractJsonSerializer. Пример приведен на рис. 10. Наконец, если вы предпочитаете использовать более надежный инструментальный набор для разработки под Android и iOS, зайдите по ссылке github.com/microsoft-dpe, рекомендуемой Microsoft.
Рис. 9. Код для Android, разбирающий JSON-данные
// HttpClient используется для взаимодействия с веб-сервисом HttpClient httpclient = new DefaultHttpClient(); String url = "http://your_hosted_service_name.cloudapp.net/"+ "FastMotorcycleListService.svc/list/Bruno"; // Это будет массивом, который мы должны будем преобразовать, // чтобы получить данные от веб-сервиса JSONArray listItems = null; String jason = null; // Настраиваем RESTful-вызов для получения данных через GET HttpGet request_http_get = new HttpGet(url); // Читаем JSON-данные и назначаем их ListView try { // Заполняем объект response, используя request HttpResponse response_http_get = httpclient.execute(request_http_get); // Length представляет количество элементов данных, // возвращенных веб-сервисом RESTful long length = response_http_get.getEntity(). getContentLength(); // Объект entity превращается в данные, // поступающие от веб-сервера HttpEntity entity = response_http_get.getEntity(); // Считываем байты – по одному за раз InputStream stream = entity.getContent(); // Создаем буфер под последовательность байтов byte[] buffer = new byte[(int) length]; // Читаем байты от веб-сервиса RESTful. После этого цикла // мы получаем нечто вроде ["busa","gxr1000","ninja250"]. for (int i = 0; i < length; i++) { buffer[i] = (byte) stream.read(); } // Создаем массив строк jason = new String(buffer); // Преобразуем JSON-массив в Android ListBox listItems = new JSONArray(jason); } catch (Exception e) { System.out.println(e); }
Рис. 10. Код на C#, разбирающий JSON-данные
private void LoadList() { string uri = @"http://your_hosted_service_name.cloudapp.net/"+ "FastMotorcycleListService.svc/list/Bruno"; var webRequest = (HttpWebRequest)WebRequest.Create(uri); webRequest.Method = "GET"; try { webRequest.BeginGetResponse(new AsyncCallback((result) => { var webResponse = (HttpWebResponse)webRequest.EndGetResponse(result); if (webResponse.StatusCode == HttpStatusCode.OK) { var jsonDeserializer = new DataContractJsonSerializer(typeof(List<string>)); List<string> items = (List<string>)jsonDeserializer.ReadObject( webResponse.GetResponseStream()); shoppingListBox.Dispatcher.BeginInvoke(new Action(() => { shoppingListBox.Items.Clear(); foreach (var item in items) { shoppingListBox.Items.Add(item); } })); } }), null); } catch { // Игнорируем } }
Доступ к целому спектру устройств
Поскольку веб-сервисы RESTful, размещаемые в Windows Azure, опираются на HTTP, с ними может взаимодействовать любое клиентское приложение, поддерживающее этот протокол. Это открывает разработчикам возможности работы с широким спектром устройств, так как большинство из них подпадает под эту категорию. Хотя мы рассматривали в этой статье мобильные платформы, такие реализации JavaScript, как jQuery, тоже способны использовать веб-сервисы RESTful. Независимо от того, по какому пути пойдет развитие UI на мобильных устройствах, всегда имеет смысл опираться на простые, открытые и основанные на HTTP архитектуры веб-сервисов.