Windows Phone 7 поддерживает push-уведомления — вид уведомлений, которые отправляются на устройство из веб-службы, когда происходит новое событие, связанное с приложением, и конечный пользователь должен быть уведомлен об этом. Например, если это почтовый клиент, это может быть уведомление о новом сообщении, которое было загружено в папку «Входящие». Нажатие на уведомление позволит пользователю открыть приложение и проверить, что происходит.
В этой статье я покажу, как создать приложение для Windows Phone 7, а также эмулятор службы, который будет отправлять уведомления.
Приложение для Windows Phone 7
Прежде всего, создайте простое приложение для Windows Phone 7.
Я удалил весь контент пользовательского интерфейса с главной страницы и оставил его пустым — здесь я не буду работать с пользовательским интерфейсом и не будет никаких хуков пользовательского интерфейса для запуска какого-либо конкретного действия. Поэтому часть моей страницы на XAML довольно проста:
<phone:PhoneApplicationPage
x:Class="NotificationTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
shell:SystemTray.IsVisible="True">
</phone:PhoneApplicationPage>
Опять же, это не случай функционального приложения. Теперь о функциональной части.
Push-уведомления доставляются на телефон не напрямую из веб-службы, а через «прокси» — службу push-уведомлений Microsoft ( MPNS ). Чтобы принимать уведомления от MPNS, в приложении должен быть настроен канал, который будет доставлять уведомления, связанные с ним. Каждый канал имеет свой уникальный URI, и этот URI назначается вам Microsoft.
Итак, первое, что я собираюсь сделать, это настроить канал — объявить уникальный экземпляр HttpNotificationChannel, который является членом пространства имен Microsoft.Phone.Notification . Вот что я делаю во время инициализации приложения:
HttpNotificationChannel channel = HttpNotificationChannel.Find("NotificationTest_WP7");
if (channel == null)
{
channel = new HttpNotificationChannel("NotificationTest_WP7");
channel.Open();
}
channel.BindToShellToast();
channel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(channel_ChannelUriUpdated);
channel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(channel_ErrorOccurred);
Debug.WriteLine(channel.ChannelUri);
Примечание: Этот код помещается внутри приложения () конструктор в App.xaml.cs .
Я открываю канал и явно показываю, что он будет использоваться для уведомлений о тостах. Как вы можете видеть здесь, я ссылаюсь на два дополнительных обработчика событий — ChannelUriUpdated и ErrorOccured . Эти обработчики событий будут отображать сообщение в окне вывода, в зависимости от результата инициализации канала уведомлений.
void channel_ErrorOccurred(object sender, NotificationChannelErrorEventArgs e)
{
Debug.WriteLine("An error occured while initializing the notification channel");
Debug.WriteLine(e.Message);
}
void channel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)
{
Debug.WriteLine(e.ChannelUri);
}
Метод ChannelUriUpdated является бесплатным, но я использую его для определения URI, который Micosoft назначит для моего приложения, поэтому я могу отправлять уведомления в это конкретное местоположение.
На данный момент вы в значительной степени сделали с мобильным приложением. Запустите его и взгляните на диалог вывода . Вы должны увидеть новый назначенный URI для канала, так как вы впервые используете это приложение с указанным каналом.
Вот что вы должны получить (URI должен быть похож на тот, что показан на рисунке ниже):
Итак, у вас есть канал URI. Теперь давайте спроектируем приложение службы WCF, которое будет отправлять данные в вышеупомянутый канал.
Сервисное приложение
Перед созданием приложения, если вы используете Windows 7 или Windows Vista, обязательно запустите Visual Studio 2010 от имени администратора . Поскольку приложение, над которым я работаю, будет хостом для службы, оно будет работать с системными компонентами, которые требуют административных привилегий.
После запуска создайте консольное приложение. Этого будет достаточно для размещения простого сервиса WCF.
По умолчанию приложение ориентировано на клиентский профиль .NET Framework 4.0 . Поскольку я буду работать с WCF, мне нужно изменить целевую платформу на .NET Framework 4.0 , чтобы получить доступ к пространству имен System.ServiceModel.Web .
Добавьте ссылку на System.ServiceModel и System.ServiceModel.Web после изменения целевой структуры. Также не забудьте добавить с помощью System.ServiceModel и System.ServiceModel.Web в заголовок класса.
Теперь создайте интерфейс, который определит один базовый метод, который будет иметь служба, которая будет запускать уведомление.
[ServiceContract]
interface IService
{
[OperationContract]
[WebGet]
string SendNotification(string message);
}
Фактический класс, который реализует интерфейс выше, это:
public class WCFService : IService
{
public string SendNotification(string message)
{
string channelURI = "PUT_YOUR_CHANNEL_URI_HERE";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(channelURI);
request.Method = "POST";
request.ContentType = "text/xml";
request.Headers.Add("X-NotificationClass", "2");
request.Headers.Add("X-WindowsPhone-Target", "toast");
string notificationData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<wp:Notification xmlns:wp=\"WPNotification\">" +
"<wp:Toast>" +
"<wp:Text1>WP7 TOAST</wp:Text1>" +
"<wp:Text2>"+ message + "</wp:Text2>" +
"</wp:Toast>" +
"</wp:Notification>";
byte[] contents = Encoding.Default.GetBytes(notificationData);
request.ContentLength = contents.Length;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(contents, 0, contents.Length);
}
string notificationStatus;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
notificationStatus = response.Headers["X-NotificationStatus"];
}
return notificationStatus;
}
}
Он в основном создает HTTP-запрос к каналу для передачи данных уведомления, который структурирован в конверте XML, описанном здесь . Заголовки, которые добавляются в запрос, устанавливают тип уведомления. После выполнения запроса я возвращаю статус уведомления, чтобы проверить, было ли оно отправлено или нет.
Теперь в основном теле приложения мне нужно как-то разместить службу, которая будет выполнять метод SendNotification . Для этого я использую экземпляр WebServiceHost, чтобы указать местоположение, и ServiceEndpoint (член System.ServiceModel.Description ), чтобы указать конечную точку, где можно получить доступ к службе.
WebServiceHost host = new WebServiceHost(typeof(WCFService), new Uri("http://localhost:1234"));
ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(IService), new WebHttpBinding(), "");
host.Open();
Выбранный мною порт является абсолютно случайным, поэтому вы можете указать другой, если он доступен.
Здесь я хочу отправлять уведомления, пока пользователь не введет команду выхода. Поэтому я собираюсь использовать цикл while:
string message = Console.ReadLine();
while (message != "exit")
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:1234/SendNotification?message=" + message.Trim());
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
Console.WriteLine(reader.ReadToEnd());
}
}
Console.ReadLine();
}
host.Close();
Environment.Exit(0);
Сообщение передается службе WCF через параметр сообщения, который был определен в определяющем интерфейсе. Отправляя запрос в службу и вызывая метод SendNotification , я могу передать сообщение в MPNS , и оно передаст его устройству с зарегистрированным каналом.
ПРИМЕЧАНИЕ. Чтобы увидеть уведомление, приложение с соответствующим зарегистрированным каналом не должно быть активным.
Вот что вы должны получить в конце: общая рекомендация состоит в том, чтобы не злоупотреблять всплывающими уведомлениями, а передавать их только тогда, когда происходит важное событие, связанное с приложением, поскольку это отвлекает внимание и в конечном итоге пользователь может раздражать их. (в случае, если они передаются часто) и заблокировать их.
ПРИМЕЧАНИЕ. Вы также можете вызвать службу WCF из своего веб-браузера, и результат будет таким же.