Динамичность и активность. Часть 2. Создание и отладка служб для динамических плиток

В части 1 этого цикла статей мы рассмотрели характер обновления плиток, обновления индикаторов событий и характер всплывающих уведомлений, которые "оживляют" весь пользовательский интерфейс в Windows 8. В частности, мы рассмотрели, как эти уведомления сочетаются с полезными нагрузками XML, которые формируются локально из запущенного приложения или фоновой задачи или могут по требованию предоставляться интернет-службой.

Вы можете легко разработать и отладить формирование полезной нагрузки XML и ее распределение из запущенного приложения с помощью Visual Studio Ultimate 2012 или Visual Studio Express 2012 для Windows 8. Всю необходимую информацию вы можете найти в примере плиток приложения и индикаторов событий, примере вспомогательных плиток и примере запланированных уведомлений.

Несколько сложнее осуществляется разработка и отладка веб-службы, поддерживающей периодические обновления и push-уведомления. Соответствующие операции на стороне клиента хорошо описаны в примере стороны клиента для push-уведомлений и периодических уведомлений, однако чтобы этим примером можно было воспользоваться, потребуется несколько служб. В данной статье мы рассматриваем разработку служб, поддерживающих периодические уведомления для обновлений плиток и индикаторов событий, уделяя особое внимание использованию средств Visual Studio и localhost для отладки служб перед их развертыванием в рабочей среде. Мы также начнем изучать использование компонента Windows Azure Mobile Services для той же цели, который, как мы увидим в части 3, очень полезен для поддержки push-уведомлений.

Основополагающий характер служб

Что именно делает служба, поддерживающая периодические обновления плиток и индикаторов событий? Давайте начнем с рассмотрения самого понятия "служба", так как часто оно кажется разработчикам, занимающимся в основном клиентскими приложениями, немного пугающим.

Если не вдаваться в подробности, служба — это некоторый фрагмент кода, расположенный на веб-сервере и выполняемый на нем по соответствующему HTTP-запросу. HTML-страницы (HTM или HTML) отличаются от службы: поскольку для них отсутствует код на стороне сервера, сервер просто возвращает текст такой страницы, а вся обработка осуществляется на клиенте (включая запуск содержащегося на этой странице клиентского сценария). Однако при наличии для этой страницы универсальных кодов ресурса (URI), оканчивающихся на PHP, ASP, ASPX, CGI, CSHTML или любое количество других серверных расширений, она является "службой" в самом общем смысле этого слова.

Служба отвечает за прием клиентского HTTP-запроса, обработку аргументов, включенных в URI, и возврат соответствующего текстового ответа. Для веб-страниц, созданных с помощью таких технологий, как PHP или ASP.NET, этот ответ должен иметь формат HTML-кода. Службы, реализующие веб-API, например в Facebook и Twitter (да и тысячи других), обычно принимают в строках URI-запросов (или в заголовке запроса) любое число параметров и возвращают данные либо XML, либо JSON. (Следует отметить, что здесь мы говорим о службах, построенных на базе архитектуры representational state transfer, или REST, а не о службах, основанных на других протоколах, таких как SOAP, поскольку сейчас архитектура REST наиболее распространена.)

Таким образом, службой, предоставляющей периодические обновления плиток и индикаторов событий, является та служба, которая присутствует по URI, выдаваемому приложением операционной системе Windows, и отвечает на HTTP-запросы соответствующей полезной нагрузкой XML. Эта полезная нагрузка содержит элементы, соответствующие любому поддерживаемому шаблону, где ссылки на изображения даются в виде других URI (встроенное кодирование не поддерживается). Конкретная информация, входящая в состав полезной нагрузки, может быть получена из любого источника, немного позднее мы рассмотрим это более подробно.

Независимо от указанных особенностей все такие службы имеют одинаковую структуру, которая принимает и обрабатывает запрос и создает XML-ответ. А теперь я расскажу, как создать такую базовую структуру.

Создание служб

Для создания и отладки служб вы можете использовать любые удобные средства, поддерживающие выбранный язык для стороны сервера. В этом описании мы уделим основное внимание Visual Studio, а именно Visual Studio Ultimate 2012 и Visual Studio Express 2012 для Web. Второй продукт предоставляется бесплатно и распространяется параллельно с уже знакомым вам аналогичным продуктом для Windows. Чтобы установить его, запустите установщик веб-платформы, с помощью которого вы также можете установить другие связанные с продуктом технологии, например PHP и WebMatrix. Это позволяет использовать разные языки для создания служб.

В качестве простого примера приведем полный код службы PHP, ответ которой состоит из полезной нагрузки XML обновления индикатора событий, где в качестве значения индикатора событий установлен текущий день месяца (по часам сервера, не забывайте об этом). Этот код взят из примера сайта HelloTiles, включенного в главу 13 моей бесплатной электронной книги Programming Windows 8 Apps with HTML, CSS, and JavaScript (Программирование приложений для Windows 8 на HTML, CSS и JavaScript):

 <?php
    echo '<?xml version="1.0" encoding="utf-8" ?>';
    echo "<badge value='".date("j")."'/>";
?>

Вы можете опробовать эту службу в работе. Выберите ссылку на сайте Windows Azure https://programmingwin8-js-ch13-hellotiles.azurewebsites.net/dayofmonthservice.php, которую я настроил специально для этого, и вы увидите, что возвращается примерно следующий XML-код:

 <?xml version="1.0" encoding="UTF-8"?>
<badge value="24"/>

Попробуйте использовать тот же самый URI в примере push- и периодических уведомлений на стороне клиента, сценарий 5 — опрос на наличие обновлений индикаторов событий. При первом запуске приложения (в Visual Studio Express для Windows), его плитка отображается на начальном экране следующим образом:

Плитка опроса на наличие обновлений индикаторов событий

Теперь введите приведенный выше URI в текстовом поле из сценария 5, нажмите кнопку [Start periodic updates] (Запустить периодические обновления) и при наличии подключения к сети вы скоро увидите на плитке примера числовой индикатор событий:

Плитка с числовым индикатором событий

Обратите внимание на то, что операционная система Windows пытается выполнить опрос на наличие обновления, как только приложение запускает периодические обновления, после чего продолжает запускать опрос с заданным интервалом.

Более полный пример PHP см. в статье Эффективное использование плиток (часть 2), где полнее описана настройка обновления плитки. В данном примере гипотетическая функция get_trucks_from_database отправляет в базу данных запрос с использование почтового индекса, включенного в параметры строки URI-запроса, а затем по результатам этого запроса создает XML-ответ.

Данная служба обладает очень широкими возможностями. Например:

  • С помощью приведенной выше PHP-службы дня месяца приложение может указать в строке запроса свой местный часовой пояс, чтобы получить уточненную дату, так как сервер вполне может располагаться в другом часовом поясе.
  • Служба прогноза погоды может использовать значения широты и долготы из URI для получения сведений о текущих условиях для данного расположения.
  • Служба может в динамическом режиме создавать изображения и сохранять их на веб-сервере, а затем вставлять соответствующие URI в полезную нагрузку XML.
  • Служба может отправлять свои собственные запросы в другие службы для получения дополнительных данных, отобранных в соответствии с параметрами строки запроса (позднее мы остановимся на этом подробнее).
  • Если приложение разрешает использование очереди для обновлений плиток (см. описание метода EnableNotificationQueue), оно может указать до пяти отдельных URI для опроса на наличие периодических обновлений, как показано в сценарии 4 примера push- и периодических уведомлений на стороне клиента. В эту очередь обновлений плиток включается обновление для каждого из URI. Конечно, в целях дополнительной настройки каждый из таких URI может иметь собственную строку запроса, чтобы одна служба могла самостоятельно обработать все запросы.
  • В строку запроса приложение может включить идентификатор пользователя, чтобы служба могла запросить в хранилищах данных сведения о журнале тренировок этого пользователя, его игровых рекордах, новостях из веб-каналов, в которых зарегистрировался пользователь, и так далее. В таких случаях идентификатор пользователей может содержать личные сведения, поэтому приложение должно обеспечивать соответствующий уровень конфиденциальности. Это значит, что приложение должно шифровать имя пользователя в строке запроса или использовать URI https://.

Примечание. В механизме периодических обновлений Windows нет средств для проверки подлинности пользователей с помощью данной службы. Такой уровень поддержки достигается только посредством push-уведомлений (либо в корпоративных сценариях с объявленной в манифесте возможностью корпоративной аутентификации).

Конечно же, службы можно создавать с применением и других технологий. Хорошим выбором станет ASP.NET, так как вы можете реализовать такую же библиотеку Notifications Extensions (написанную на C#), которую можно использовать в приложении для упрощения создания хорошо структурированных полезных нагрузок XML.

В качестве небольшого примера давайте рассмотрим простейшую службу WebMatrix, которую я создал для образца службы HelloTiles в главе 13 своей книги (см. дополнительные материалы). Эта служба просто возвращает фиксированную полезную нагрузку XML (с привязками как для квадратных, так и для широких плиток) и по структуре аналогична первому примеру ASP.NET, приведенному в статье Эффективное использование плиток (часть 2):

 @{
  //
  // This is where any other code would be placed to acquire the dynamic content
  // needed for the tile update. In this case we'll just return static XML to show
  // the structure of the service itself.
  // 
  var weekDay = DateTime.Now.DayOfWeek;
}
<?xml version="1.0" encoding="utf-8" ?>
<tile>
    <visual lang="en-US">
        <binding template="TileSquarePeekImageAndText02" branding="none">
            <image id="1" src="https://www.kraigbrockschmidt.com/images/Liam07.png"/>
            <text id="1">Liam--</text>
            <text id="2">Giddy on the day he learned to sit up!</text>
        </binding>
        <binding template="TileWideSmallImageAndText04" branding="none">
            <image id="1" src="https://www.kraigbrockschmidt.com/images/Liam08.png"/>
            <text id="1">This is Liam</text>
            <text id="2">Exploring the great outdoors!</text>
        </binding>
    </visual>
</tile>

Если вы решили опробовать данную службу в сценарии 4 примера push- и периодических уведомлений на стороне клиента, она развертывается в https://programmingwin8-js-ch13-hellotiles.azurewebsites.net/Default.cshtml. В этом случае через несколько секунд вы увидите следующие обновления плиток (широкой слева и двух частей обзорной плитки справа):

liam_1

liam_2liam_tile

А теперь давайте реализуем то же самое с помощью библиотеки Notification Extensions. Прежде всего, вам следует создать версию библиотеки для своего веб-сайта следующим образом:

  1. Перейдите к примеру плиток и индикаторов событий приложения и скопируйте папку Notifications Extensions из этого проекта в свою папку. (Вы также можете установить библиотеку непосредственно из Visual Studio, щелкнув проект правой кнопкой мыши, выбрав пункт [Manage NuGet Packages…] (Управление пакетами NuGet) и выполнив поиск NotificationsExtensions.WinRT. Однако при этом библиотека включается в состав существующего проекта приложения, а в данном случае нам необходима автономная библиотека DLL.)
  2. В Visual Studio Express для Windows откройте файл NotificationsExtensions.csproj.
  3. В обозревателе решений щелкните проект NotificationExtensions правой кнопкой мыши, выберите пункт "Свойства" и внесите следующие изменения:
    1. В параметрах приложения измените "Тип вывода" на Библиотека классов (библиотека DLL). Это необходимо для использования данной библиотеки с сайтом ASP.NET.
    2. В параметрах построения измените значение конфигурации на Все конфигурации, измените символы условной компиляции на NETFX_CORE; WINRT_NOT_PRESENT и убедитесь, что в нижней части страницы выбран файл документации XML. Флаг WINRT_NOT_PRESENT разрешает компиляцию библиотеки без WinRT.
  4. Выберите целевой объект отладки или выпуска, а затем щелкните проект Notifications Extensions правой кнопкой мыши и выберите пункт Построение.

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

  1. В Visual Studio Express для Web, щелкните проект веб-сайта правой кнопкой мыши и выберите команду Добавить > Добавить папку ASP.NET > Bin, если ваш сайт еще не имеет папки Bin.
  2. Щелкните эту папку Bin правой кнопкой мыши и выберите пункт Добавить ссылку…. В окне Добавление ссылки перейдите в папку bin\Debug или bin\Release проекта Notifications Extensions и выберите находящуюся там библиотеку DLL.

Если вы используете Visual Studio Ultimate, то при необходимости можете добавить проект Notification Extensions в свое решение веб-сайта, так как данное средство поддерживает оба типа проектов. Только следите за тем, чтобы не выполнить развертывание исходного кода для этого проекта на свой веб-сервер!

Помните и о том, что в случае построения сайта для локального выполнения в браузере (как описано в разделе "Отладка" ниже) при добавлении ссылки на System.Runtime может возникнуть ошибка. Чтобы исправить ситуацию, откройте файл web.config и измените значение элемента compilation следующим образом:

 <compilation debug="true" targetFramework="4.0">
  <assemblies>
    <add assembly="System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> 
  </assemblies>
</compilation>

После этого можно использовать следующую страницу (с именем DefaultNE.aspx), которая выдает те же результаты, что и приведенный ранее жестко заданный пример:

 <?xml version="1.0" encoding="utf-8" ?>
<%@ Page Language="C#" %>
<script runat="server">   1:  
   2:     public string GenerateTileXML()
   3:     {
   4:         // Construct the square template
   5:         NotificationsExtensions.TileContent.ITileSquarePeekImageAndText02 squareTile = 
   6:             NotificationsExtensions.TileContent.TileContentFactory.CreateTileSquarePeekImageAndText02();
   7:         squareTile.Branding = NotificationsExtensions.TileContent.TileBranding.None;        
   8:         squareTile.Image.Src = "https://www.kraigbrockschmidt.com/images/Liam07.png";
   9:         squareTile.TextHeading.Text = "Liam--";
  10:         squareTile.TextBodyWrap.Text = "Giddy on the day he learned to sit up!";
  11:         
  12:         // Construct the wide template
  13:         NotificationsExtensions.TileContent.ITileWideSmallImageAndText04 wideTile =
  14:             NotificationsExtensions.TileContent.TileContentFactory.CreateTileWideSmallImageAndText04();
  15:         wideTile.Branding = NotificationsExtensions.TileContent.TileBranding.None;
  16:         wideTile.Image.Src = "https://www.kraigbrockschmidt.com/images/Liam08.png";
  17:         wideTile.TextHeading.Text = "This is Liam";
  18:         wideTile.TextBodyWrap.Text = "Exploring the great outdoors!";
  19:                 
  20:         // Attach the square template to the notification
  21:         wideTile.SquareContent = squareTile;
  22:         wideTile.Lang = "en-US";
  23:         
  24:         // The wideTile object is an XMLDOM object, suitable for issuing tile updates
  25:         // directly. In this case we just want the XML text.
  26:         return wideTile.ToString();        
  27:     }

</script>
<%

   1:  = GenerateTileXML() 

%>

Вы можете открыть данную службу по адресу https://programmingwin8-js-ch13-hellotiles.azurewebsites.net/DefaultNE.aspx и получить практически тот же самый XML-код, имеющий лишь незначительные отличия. Вставка URI в сценарий 4 примера push- и периодических уведомлений на стороне клиента также обеспечит те же обновления плиток, что и прежде.

Отладка служб

Создание успешного обновления плитки или индикатора событий подразумевает правильное форматирование XML-кода в ответе службы: В противном случае Windows отклоняет XML-код. Это является аргументом в пользу использования библиотеки Notifications Extensions, так как она значительно сокращает количество ошибок, которые вы могли допустить во время работы.

Но что если служба вообще работает неправильно? Как вы можете диагностировать и отладить процесс обработки ею запросов и создания ответа?

На самом деле при первом использовании приведенного выше кода службы ASP.NET обновления у меня не отображались, так как в начале ответа XML присутствовал символ новой строки. Именно поэтому заголовок <?xml ?> стоит в первой строке файла, а не после директивы <%@ Page %> , и отсутствуют дополнительные переводы строки.

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

Соответствующий метод заключается в использовании localhost на компьютере разработки, что позволяет запускать службу и осуществлять ее отладку локально одновременно с выполнением тестового клиентского кода, такого как примеры SDK.

Наличие localhost означает выполнение локального веб-сервера, такого как службы IIS или Apache. Чтобы включить службы IIS в Windows (они встроены в операционную систему), выберите Панель управления > Включение или отключение компонентов Windows. Установите флажок "Службы IIS" в верхнем уровне списка, как показано ниже, чтобы установить соответствующие основные компоненты:

Диалоговое окно "Компоненты Windows" с установленным флажком "Службы IIS"

После установки служб IIS локальный сайт, на который указывает адрес https://localhost/ , помещается в папку c:\inetpub\wwwroot. Именно в нее следует помещать, например, страницу PHP, описанную в прошлом разделе, чтобы можно было использовать такой URI, как https://localhost/dayofmonthservice.php, в примерах для стороны клиента.

Чтобы использовать PHP совместно с IIS, вам может потребоваться установить данный компонент через установщик веб-платформы Майкрософт, иначе код для стороны сервера будет работать неправильно. После установки PHP попробуйте ввести в браузере URI для локальной страницы PHP. Если отображается сообщение об ошибке "Обработчик PHP53_via_FastCGI содержит поврежденный модуль" (да уж, это здорово помогло), вернитесь в указанное ранее диалоговое окно "Включение или отключение компонентов Windows", выберите Службы IIS > Службы Интернета > Компоненты разработки приложений, установите флажок CGI и нажмите кнопку ОК. После установки модуля CGI страница PHP должна работать правильно.

После размещения localhost вы можете выполнять отладку служб на собственном компьютере, используя Visual Studio Express для Web или Visual Studio Ultimate. Вы также можете использовать Visual Studio Express для Web одновременно с Visual Studio Express для Windows в целях совместной отладки клиентского и серверного кода.

При запуске службы или веб-сайта в отладчике Visual Studio (для Web) они выполняются в браузере с таким URL-адресом, как https://localhost:<порт>/ , где <порт> назначается для проекта случайным образом. Например, при запуске страницы DefaultNE.aspx из предыдущего раздела в Visual Studio Express для Web она открылась в Internet Explorer с URI https://localhost:52568/HelloTiles/DefaultNE.aspx. Если бы я задал в коде этой страницы точку останова, отладчик остановил бы выполнение в данной точке.

Точки останова срабатывают и в том случае, если вы используете такой же URI localhost в клиентском коде для активации запросов. Например, если я запускаю пример push- и периодических уведомлений на стороне клиента в Visual Studio Express для Windows и вставляю URI в сценарий 4, при выполнении операционной системой Windows запроса Visual Studio Express для Web сразу же остановит мою службу в отладчике. После этого я смогу поэтапно выполнить данный код (к счастью, в этом случае Windows терпеливо ожидает) и убедиться, что создается правильный ответ. Если ответ неправильный, я могу исправить код и перезапустить службу на localhost.

Если вы уверены, что служба работает правильно, можно отправить ее на рабочий веб-узел (или в промежуточную среду) и осуществить окончательное тестирование в рабочей среде.

Обратите внимание, что для такого использования localhost запуск клиентского кода в отладчике не требуется. Если же вы запускаете этот код, для правильной работы localhost в Visual Studio должен быть включен соответствующий параметр. По умолчанию этот параметр выбран, но если вам потребуется изменить его, найдите его в свойствах проекта в области Отладка > Разрешить петлевой адрес в локальной сети:

Параметр "Разрешить петлевой адрес в локальной сети"

Данные из внешних источников

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

Чтобы упростить себе работу, мы можем воспользоваться тем фактом, что Windows отправляет запросы в вашу службу с интервалом 30 минут или более, как того требует клиентский API. Таким образом, у вас есть достаточно много времени, когда другие процессы на стороне сервера могут выполнять внешние запросы для отслеживания предупреждений о погоде, списков лидеров, RSS-каналов и любых других элементов, для которых имеется веб-API. Эти процессы сохраняют результаты в вашей базе данных, после чего они становятся доступны для запроса (в синхронном режиме) службе периодических уведомлений после получения следующего запроса.

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

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

database_servers_graph

Использование Windows Azure Mobile Services со службами периодических обновлений

Когда вы начнете разбираться в серверных службах, обеспечивающих поддержку динамических плиток и других уведомлений, и создавать их, вы просто обязаны ознакомиться с компонентом Windows Azure Mobile Services, который я для краткости называю AMS. Кроме существенного упрощения push-уведомлений, описанного в части 3 этого цикла статей, Windows Azure Mobile Services можно использовать для различных способов реализации поддержки служб периодических обновлений:

  • В мобильной службе вы можете создать запланированные фоновые задания, способные отправлять запросы в другие службы и сохранять результаты в вашей базе данных. Соответствующий пример для получения твитов из Twitter см. в статье о планировании повторяющихся заданий в мобильных службах.
  • При создании базы данных SQL Server в Windows Azure Mobile Services (или ином компоненте Windows Azure) ее доступность аналогичная любой другой размещенной в Интернете базе данных SQL Server, поэтому вы можете использовать ее с веб-сайтов и из других служб, включая те из них, которые написаны на PHP.
  • Windows Azure Mobile Services значительно упрощает вставку записей в базу данных из клиентского приложения с помощью Mobile Services SDK.
  • Кроме мобильных служб, компонент Windows Azure может размещать серверные процессы, написанные на разных языках, включая Node.js, Python, Java, PHP и .NET.

В будущем в Azure Mobile Services появится компонент "операции служб", позволяющий вам создавать произвольные конечные точки http, включая службу периодических уведомлений.

Дополнительные сведения о Windows Azure см. на сайте https://www.windowsazure.com. Ознакомительные видеозаписи см. в учебниках по Windows Azure Mobile Services на канале 9.

Разобравшись с созданием служб периодических уведомлений, мы готовы продолжить знакомство с push-уведомлениями. Push-уведомления необходимы, когда требуется выдавать обновления чаще, чем это допускается периодическими уведомлениями, главным образом по запросу (на это и указывает часть названия: "push" — "толкать"). К этой теме мы возвратимся в части 3 данного цикла статей, где подробнее остановимся на Azure Mobile Services.

Крэйг Брокшмидт (Kraig Brockschmidt)

Руководитель программы, рабочая группа по экосистеме Windows

Автор книги Programming Windows 8 Apps in HTML, CSS, and JavaScript (Программирование приложений для Windows 8 на HTML, CSS и JavaScript)