Эта статья посвящена масштабируемости и взаимодействию — двум характеристикам, необходимым в архитектурах, которые должны поддерживать множество современных мобильных платформ, популярных в настоящее время, с потенциальной аудиторией в миллионы пользователей. В табл. 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 архитектуры веб-сервисов.