Статьи

Уведомления Windows 8: Push-уведомления через веб-сайты Windows Azure (часть 3)

 Наконец-то пришло время добраться до «лазурной» части этого трехчастного! Те из вас, кто не читал Часть 1 и Часть 2, возможно, захотят, по крайней мере, просмотреть эти сообщения для контекста. Те из вас, кто знает, что я создал приложение для Магазина Windows (Boys of Summer), в котором есть push-уведомления для информирования конечных пользователей о новостях, связанных с их любимыми командами высшей лиги. Приложение Магазина Windows работает совместно с облачной службой (размещенной на веб-сайте Windows Azure ) для поддержки рабочего процесса уведомлений, и эта статья посвящена последней части головоломки, как показано ниже.

Рабочий процесс push-уведомлений с выделением облачного сервиса

В этом облачном сервисе есть два основных компонента: сайт ASP.NET MVC, который активно использует Web API, и резервное хранилище в форме базы данных MySQL. Механизм развертывания — это веб-сайт Windows Azure , в котором выбирается MySQL (поверх базы данных SQL Azure Windows ), поскольку 20-Мбайтный экземпляр MySQL включен в бесплатное предложение веб-сайтов начального уровня. Я не ожидаю, что моему приложению потребуется больше мощности, чем уже включено в этот бесплатный уровень веб-сайтов Windows Azure, но приятно знать, что я могу перейти к общей или зарезервированной модели, если Boys of Summer станет дико успешным!

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

Шаг 1. Получите свою учетную запись Windows Azure

Шаг 2. Создайте новый веб-сайт Windows Azure

Шаг 3. Настройте базу данных MySQL

Шаг 4. Создайте API для облачного сервиса

Шаг 5. Реализуйте ASP.NET MVC страницу, которая выдает уведомления

Шаг 6. Внедрить интерфейс со службой уведомлений Windows (WNS)

Шаг 7. Разверните готовое решение в Windows Azure

Шаг 1. Получите учетную запись Windows Azure

Windows AzureСуществует несколько способов получить учетную запись Windows Azure , и одним из самых простых способов «запихнуть» является 90-дневная бесплатная пробная версия . Если вы являетесь подписчиком MSDN , у вас уже есть месячное выделение часов , и все, что вам нужно сделать, это активировать льготу.

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

Шаг 2. Создание нового веб-сайта Windows Azure

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

Для Boys of Summer мне был нужен веб-сайт вместе с базой данных.

Создание нового веб-сайта с базой данных

Если вы не видите веб-сайты Windows Azure в списке на левой боковой панели или они отключены, вам нужно посетить
страницу своей учетной записи и выбрать пункт
меню
функций предварительного просмотра, чтобы включить веб-сайты (и другие функции, которые еще не полностью выпущены). ). Активация происходит за считанные минуты, если не быстрее.

Чтобы создать веб-сайт, на следующих двух экранах необходимо ввести только несколько битов информации:

Новые свойства веб-сайта Windows Azure

  • URL-адрес веб-сайта , который должен быть уникальным (в домене azurewebsites.net). Именно этот URL будет являться целью вызовов службы RESTful, сделанных из моего приложения Магазина Windows.
  • расположение центра обработки данных, в котором будет размещаться служба.
  • какой тип базы данных создать (MySQL здесь, но SQL Database также вариант).
  • имя строки подключения к базе данных.
  • имя сервера базы данных.
  • расположение центра обработки данных , в котором размещена база данных MySQL , которая должна быть той же самой, что и сам веб-сайт; в противном случае вы понесете ненужную задержку, а также будете платить штрафы за пропускную способность.

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

После ввода необходимых данных для предоставления сайта и базы данных требуется всего одна или две минуты, в течение которых статус отражается на портале. Когда сайт доступен, его можно выбрать из списка веб-сайтов на портале Azure, чтобы открыть экран «Начало работы» ниже:

Новая страница "Начало работы"

На данный момент сайт (с контентом по умолчанию) фактически активен, что можно подтвердить, нажав кнопку BROWSE в строке меню в нижней части экрана.

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

  1. Я буду использовать строку подключения MySQL для создания таблиц, необходимых для хранения URI уведомлений для различных клиентов, и
  2. Я сохраню профиль публикации (как локальный файл) для последующего импорта в Visual Studio 2012. Это позволит мне развернуть приложение ASP.NET непосредственно в Windows Azure. Помните, что этот файл содержит конфиденциальную информацию, позволяющую развертывание в облаке, поэтому будьте осторожны с файлом настроек публикации.

Основная информация для построения сервиса Web API

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

Шаг 3. Настройте базу данных MySQL

В реализации службы Web API я использую Code First Entity Framework (EF) вместе с базовым шаблоном репозитория на ОЧЕНЬ простой модели данных, которая абстрагирует две таблицы с определениями столбцов, показанными ниже.

Имя таблицы Имя столбца Тип столбца Использование столбца
регистрации Мне бы INT (11) значение автоинкремента (уникальный и первичный ключ)
Uri УАКСНАК (1024) URI канала уведомлений
TeamID УАКСНАК (10) короткое имя для бейсбольной команды, связанной с каналом уведомлений
команды Мне бы УАКСНАК (10) краткое название бейсбольной команды (уникальный и первичный ключ)
название УАКСНАК (63) дружеское название бейсбольной команды
логотип MEDIUMBLOB изображение логотипа команды (менее 200 КБ и 1024×1024 пикселей)

Я использовал MySQL Workbench с открытым исходным кодом (с данными строки подключения на портале Windows Azure) для создания таблиц и заполнения данных в таблице команд . Есть также очень простая хранимая процедура, которая вызывается одним из сервисных методов, о которых я расскажу чуть позже в этом посте:

CREATE PROCEDURE updatechanneluri 
          (IN olduri VARCHAR(2048), IN newuri VARCHAR(1024))
BEGIN
   UPDATE registrations SET Uri = newuri WHERE Uri = olduri;
END

Поскольку я выбрал MySQL, мне нужно было установить поставщика, и, в частности, я установил Connector / Net 6.6.4, который поддерживает Entity Framework и Visual Studio 2012. На момент написания этой статьи версия Connector / Net, доступная через NuGet, не поддерживалась. ,

Шаг 4. Создайте API для облачной службы

Существует множество вариантов создания облачной службы на веб-сайтах Windows Azure — .NET, PHP, Node.js — и нескольких инструментов, таких как Visual Studio и Web Matrix . Я решил использовать ASP.NET MVC и веб-API в .NET 4.5 в Visual Studio 2012 (как вы можете видеть ниже).

Создание сайта ASP.NET Web API

Если вы новичок в веб-API ASP.NET MVC , я настоятельно рекомендую ознакомиться с короткой заставкой Джона Гэллоуэя, посвященной веб-API ASP.NET, часть 1: ваш первый веб-API, чтобы дать вам обзор компонентов проекта и общего архитектурного подхода.

Мой сервис включает в себя три контроллера : контроллер по умолчанию, контроллер регистрации и контроллер команд. Home Controller предоставляет веб-страницу по умолчанию для отправки уведомлений о тостах; Я посмотрю на это в шаге 6.

Два других контроллера специально расширяют ApiController и используются для реализации различных вызовов службы RESTful. Неудивительно, что каждый из них напрямую соответствует одному из двух классов модели данных Entity Framework (и, соответственно, таблицам MySQL). Эти контроллеры более или менее выполняют CRUD-операции над этими двумя таблицами.

Шаг 4.1. Программирование TeamsController

Приложение не изменяет какую-либо информацию о команде, поэтому необходимо выполнить только две операции чтения:

public Team Get(String id) 

извлекает информацию о данной команде по ее идентификатору: класс Team является одним из двух классов сущностей в моей модели Entity Framework.

Этот метод вызывается с помощью HTTP GET запроса , совпадающего с маршрутом http://boysofsummer.azurewebsites.net/api/teams/{id}, где идентификатор является коротким именем для команды, как RedSox или иволги .

public HttpResponseMessage GetLogo(String id, String fmt)

извлекает необработанные байты файла изображения для логотипа команды. Возврат значения HttpResponseMessage (в сравнении с фактическими данными) позволяет установить заголовки ответа (например, Content-type на «image / png»). Реализация этого метода в конечном счете достигает таблицы команд в MySQL, чтобы получить логотип, а затем записывает необработанные байты этого логотипа в виде StreamContent в возвращенном HttpResponseMessage . Если у команды нет файла логотипа, возвращается код состояния HTTP 404 .

Этот метод отвечает на запрос HTTP GET, соответствующий маршруту http://boysofsummer.azurewebsites.net/api/logos/ averageid broadcast/png, где id снова является коротким именем для данной команды.

Почему я не использовал MediaTypeFormatter? Если вы работали с веб-API, вы знаете, что он использует концепцию
согласования содержимого для возврата различных представлений одного и того же ресурса с помощью
заголовка Accept: в запросе, чтобы определить тип содержимого, которое следует отправлять в ответ. Например, ресурс
http://boysofsummer.azurewebsites.net/api/teams/redsox, безусловно, ссылается на Red Sox, но возвращает ли он информацию об этой команде в виде XML? как JSON? или что-то другое?

Подход, на который я надеялся, заключался в создании MediaTypeFormatter , который работает в сочетании с согласованием содержимого, чтобы определить, как форматировать результат. Поэтому я создал средство форматирования, которое будет возвращать необработанные байты изображения и тип содержимого image / png всякий раз, когда поступает запрос для команды с заголовком Accept, указывающим image / png. Любой другой запрошенный тип будет просто по умолчанию в JSON-представлении полей этой команды.

Однако, чтобы это работало, входящий запрос GET для URI должен соответствующим образом установить заголовок Accept. К сожалению, при создании запроса шаблона тоста (в XML) вы можете указать только сам URI, а запрос, который выдается для изображения (внутренним механизмом уведомлений Windows 8), включает в себя универсальный заголовок Accept : * / *

Моим выбранным путем наименьшего сопротивления было создание отдельного метода GET ( GetLogo выше) с дополнительным параметром пути, который якобы указывает желаемый формат представления (хотя в моем упрощенном случае формат всегда PNG).

Шаг 4.2. Кодирование регистраций контроллера

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

public HttpResponseMessage Post(Registration newReg)

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

Этот метод POST вызывается приложением Магазина Windows каждый раз, когда пользователь перемещает тумблер уведомлений данной команды в положение «Вкл». Соответствующий шаблон URI: http://boysofsummer.azurewebsites.net/api/registrations, а тело запроса содержит URI канала и имя команды в формате JSON.

public HttpResponseMessage Delete(String id, String uri)

удаляет существующую запись из базы данных регистраций в ответ на отключение пользователем уведомлений для данной команды через интерфейс приложения Магазина Windows. Успешное удаление приводит к HTTP-коду 204 (без содержимого), в то время как попытка удалить несуществующую запись возвращает 404 (не найдено).

HTTP-метод DELETE здесь использует шаблон URI http://boysofsummer.azurewebsites.net/api/registrations/ndomid‹/ enjuri}, где id — это короткое имя команды, а uri — URI канала уведомления, закодированный в моей модификации Base64 .

public HttpResponseMessage Put(String id, [FromBody] UriWrapper u)

изменяет все существующие записи, соответствующие URI канала уведомлений, записанные в базе данных, с новым URI канала, предоставленным через тело сообщения. Это используется, когда указанный URI канала уведомлений клиента «истекает», и предоставляется новый, так что клиент может продолжать получать уведомления для групп, на которые он ранее подписался. Кстати, этот метод использует упомянутую ранее хранимую процедуру MySQL для более эффективного обновления потенциально нескольких строк.

Этот метод PUT соответствует шаблону URI http://boysofsummer.azurewebsites.net/api/registrations/ averageid}, где id — это предыдущий URI канала уведомлений, записанный в базе данных MySQL. Заменяющий URI передается через тело сообщения как простой объект JSON. Оба URI имеют кодировку Base64 (ish). Обновление возвращает 204 (без содержимого) независимо от того, совпадают ли какие-либо строки в таблице регистрации .

Шаг 5. Реализация ASP.NET MVC Page, которая выдает уведомления

Для примера, который я представляю здесь, я адаптировал домашнюю страницу ASP.NET MVC по умолчанию, чтобы обеспечить способ запуска уведомлений для конечных пользователей приложения Boys of Summer Windows Store. На данный момент это довольно ручной процесс, предполагающий, что кто-то сидит перед браузером — возможно, сканирует спортивные новостные издания на предмет интересных деталей для отправки. Это не невероятно масштабируемый сценарий, поэтому «в реальной жизни» может быть (полу) автоматизированный процесс, который подключается к различным RSS или другим каналам и автоматически генерирует соответствующие уведомления.

ASP.NET MVC View для отправки уведомлений

Контроллер здесь имеет два метода, GET и POST. GET — это простая однострочная строка, которая возвращает представление со списком команд, заполненных из модели через реализацию репозитория моей команды.

POST, который срабатывает при нажатии кнопки « Отправить уведомление» , является более интересным из двух методов и полностью представлен ниже со строковым комментарием.

[HttpPost]
public async Task<ActionResult> Index
       (String notificationHeader, String notificationBody, String teamName)
{
   // set XML for toast
    String toast = SetToastTemplate(notificationHeader, notificationBody,             
        String.Format("{0}api/logos/{1}", Request.Url, teamName));

    // send notifications to subscribers for given team
  List<NotificationResult> results = new List<NotificationResult>();
   foreach (Registration reg in RegistrationRepository.GetRegistrations(teamName))
   {
       NotificationResult result = 
                       await WNSHelper.PushNotificationAsync(reg.Uri, toast);
       results.Add(result);

       if (result.RequiresChannelUpdate())
           RegistrationRepository.RemoveRegistration(teamName, reg.Uri);
   }

   // show results of sending 0, 1 or multiple notifications
   ViewBag.Message = FormatNotificationResults(results);
 
   return View(TeamRepository.GetTeams().ToList());
}

Линии 2-3 Запрос POST извлекает три поля формы из представления, а именно: текст заголовка, сообщение и команда
Строки 6-7 Вспомогательный метод вызывается для форматирования шаблона XML; это просто упражнение по форматированию строк для заполнения соответствующих частей шаблона. Эта реализация поддерживает только ToastImageAndText02Template .
Линия 11 Список всех регистраций для желаемой команды возвращается из базы данных.
Линии 13-14 Уведомление отправляется для каждой регистрации, полученной с использованием вспомогательного класса, который будет объяснен в ближайшее время .
Линия 15 Список экземпляров NotificationResult записывает результат каждого уведомления, включая информацию об ошибке, если она есть. Обратите внимание, что вы никогда не узнаете, прибыло ли уведомление в пункт назначения.
Линии 17-18 Если конкретная ошибка, обнаруженная при отправке уведомления, указывает на то, что целевой канал уведомлений больше не действителен, эта регистрация удаляется из базы данных.

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

Линия 22 Краткое резюме результатов уведомления приведено на обновленной веб-странице. Если было отправлено одно уведомление, предоставляется несколько деталей; если было предпринято несколько уведомлений, отображается только количество успехов и неудач.

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

Линия 24 Как и в случае запроса GET, модель (список бейсбольных команд) перезагружается.

Шаг 6. Внедрите интерфейс со службой уведомлений Windows (WNS)

Это забавная часть: обмен между моим облачным сервисом и WNS, который выполняет всю тяжелую работу с точки зрения фактической доставки тостов на устройства — с помощью реализации, стоящей за линией 14 выше:

await WNSHelper.PushNotificationAsync(reg.Uri, toast)

WNSHelper — это класс, который я написал, чтобы абстрагировать поток сообщений между службой и WNS, и, как таковая, является более простой (но менее надежной) версией кода рецепта WNS для Windows 8, доступной в Windows Azure Toolkit для Windows 8 (источником которой является находится в / библиотеки / WnsRecipe извлеченного инструментария). Код для WNSHelper доступен в Gist (если вы хотите погрузиться глубже), но здесь это в картинках:

Поток OAuth

Во-первых, мой сервис (через метод RefreshTokenAsync ) инициирует запрос токена доступа по протоколу OAuth 2.0 . Он использует Live Services для аутентификации SID пакета и секрета клиента, которые я получил в Магазине Windows при регистрации моего приложения. SID пакета и секрет клиента должны храниться в защищенном виде как часть облачной службы, поскольку они являются учетными данными, которые позволяют любому агенту отправлять push-уведомления в соответствующее приложение.

HTTP-запрос выглядит примерно так: Обратите внимание, что SID и секрет клиента являются частью параметров формы в кодировке URL, а также grant_type и scope, которые всегда устанавливаются в значения, которые вы видите здесь.

POST https://login.live.com/accesstoken.srf HTTP / 1.1 Тип содержимого: application / x-www-form-urlencoded Хост: login.live.com Длина содержимого: 210 grant_type = client_credentials & scope = notify.windows. com & client_id = REDACTED_SID & client_secret = REDACTED_SECRET

Предполагая, что аутентификация прошла успешно, ответное сообщение будет включать в себя токен доступа, в частности токен канала- носителя , который предоставляет презентатору (или «носителю») этого токена привилегии для выполнения некоторой операции в будущих HTTP-запросах. Ответное сообщение HTTP, предоставляющее этот токен, имеет вид:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
  "access_token" : "mF_9.B5f-4.1JqM",
  "token_type" : "Bearer",
  "expires_in" : 86400
}

Токен доступа — это не более чем трудно угадываемая строка, но обратите внимание, что есть также параметр expires_in , который означает, что этот токен можно использовать только в течение дня (86400 секунд), после чего дополнительные запросы с использованием этого токена будут в результате код состояния HTTP 401 (неавторизованный). Это важно, и я вернусь к этому в ближайшее время.

После того как облачная служба получила токен-носитель, она теперь может отправлять несколько push-уведомлений в WNS, представляя этот токен в заголовке авторизации HTTP-запросов push-уведомлений. Фактический запрос отправляется на URI канала уведомлений, а тело сообщения представляет собой шаблон XML-тоста.

Ряд дополнительных заголовков HTTP также поддерживается в том числе X-WNS-Type , который используется для указания типа уведомления (тост, плитки, значок, или сырья) и X-WNS-RequestForStatus , который я использую , чтобы получить дополнительную информацию о распоряжение уведомлением.

Вот пример запроса на уведомление от моего облачного сервиса:

POST https://bn1.notify.windows.com/?token=AgYAAADCM0ruyKK… HTTP/1.1
Content-Type: application/xml
Host: bn1.notify.windows.com
Authorization: Bearer mF_9.B5f-4.1JqM
X-WNS-Type: wns/toast
X-WNS-RequestForStatus: true
Content-Length: 311 <toast> <visual>
<binding template="ToastImageAndText02">
<image id="1" src="http://boysofsummer.azurewebsites.net/api/logos/tigers/png" />
<text id="1">Breaking News!!!</text>
<text id="2">The Detroit Tigers have won the ALCS!</text>
</binding>
</visual>
</toast>

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

Если WNS возвращает код успеха, это просто означает, что он смог обработать запрос, а не то, что запрос достиг места назначения. Этот бит информации невозможно проверить. В зависимости от дополнительных заголовков X-WNS, указанных в запросе, в ответе будут отображаться некоторые заголовки, предоставляющие диагностическую и дополнительную информацию о состоянии.

Теперь, если запрос не выполнен, вам могут потребоваться определенные действия. Полный список кодов ответа HTTP хорошо документирован , но я хотел бы повторить несколько критических те , которые вы можете увидеть в рамках «нормальных» операций.

200 Успех — это хорошо
401 Несанкционированный — это может происходить обычно, когда истекает токен носителя OAuth. Служба, отправляющая уведомления, должна продолжать повторно использовать тот же токен OAuth до получения 401. Это сигнал для повторного выдачи исходного запроса OAuth (с SID и клиентским секретом) для получения нового токена.

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

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

Моя реализация проверяет все, кроме сценария регулирования. Если получен ответ 401 , код автоматически повторяет запрос на токен OAuth (но с ограниченной дополнительной проверкой ошибок). Точно так же ответ 406 (или 404 в этом отношении) приводит к удалению этой конкретной комбинации URI / команды канала из таблицы регистраций MySQL .

Шаг 7. Разверните все это

Осталось только одно! ОТПРАВИМ ЕГО! Во время разработки этого примера я смог выполнить много локальных отладок, полагаясь на Fiddler, чтобы выучить и диагностировать проблемы с моими вызовами API RESTful, поэтому вам не нужно сразу развертываться в облаке — хотя и с уровень бесплатного веб-сайта Windows Azure, для которого не требуется никаких реальных затрат. Фактически, моя разработка была в некоторой степени гибридной архитектурой, поскольку я всегда обращался к базе данных MySQL, которую я предоставлял в облаке, даже когда я выполнял свой сайт ASP.NET локально.

Когда приходит время перейти к работе, это невероятно просто благодаря возможности использовать веб-развертывание на веб-сайтах Windows Azure. Когда я подготовил сайт в начале этого поста, я скачал файл настроек публикации с портала Windows Azure. Теперь с помощью опции контекстного меню « Опубликовать…» проекта ASP.NET MVC я могу в Visual Studio 2012 (и 2010 в этом отношении) импортировать настройки из этого файла и просто нажать «Опубликовать», чтобы перенести сайт в Windows Azure.

По правде говоря, был еще один шаг — привлечение MySQL. Windows Azure не имеет установленных сборок Connector / NET и не знает, что это доступный поставщик. Это легко исправить, добавив объявление провайдера в файл web.config проекта:

  <system.data>
    <DbProviderFactories>
      <add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" 
            description=".Net Framework Data Provider for MySQL" 
            type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data" />
    </DbProviderFactories>
  </system.data>

MySQL references need to have Copy Local set to true

и убедитесь, что для каждой из ссылочных сборок MySQL свойство Copy Local имеет значение true. Это необходимо для обеспечения того, чтобы двоичные файлы копировались вместе с остальным кодом сайта ASP.NET и ресурсами ресурса.

С развернутой службой единственное, что осталось сделать, — это убедиться, что приложение Магазина Windows направляет свой трафик на новую конечную точку по сравнению с локальным хостом или чем-то еще, что использовалось при тестировании. Я просто сделал служебный URI ресурсом уровня приложения в своем приложении Windows Store C # / XAML, чтобы можно было легко переключаться между серверами.

<x:String x:Key="ServiceUri">http://boysofsummer.azurewebsites.net:12072</x:String>

Finis!

С развернутым сервисом был реализован рабочий процесс, который я представил двумя постами назад с изображением ниже! Надеемся, что это глубокое погружение дало вам лучшее понимание рабочего процесса push-уведомлений, а также больше оценило мобильные службы Windows Azure , которые абстрагируют большую часть этого низкоуровневого кода в предложение Backend-as-a-Service, которое вполне подходит для большого количества похожих сценариев.

Boys of Summer push-уведомления