Sending toast notifications on Windows Phone 7

  • submit to reddit
This article is part of the DZone Windows Phone 7 Zone, which is brought to you in collaboration with Microsoft. Visit the Windows Phone 7 Zone for additional tutorials, videos, opinions, and other resources on this topic.

Windows Phone 7 supports push notifications – the kind of notifications that are pushed to the device from a web service when a new event, connected to the application occurs and the end-user should be notified about it. For example, if it is an email client, it could be a notification about a new message that was downloaded to the inbox. Clicking on the notification will let the user open the application and check what’s going on.

In this article I will show how to create an application for Windows Phone 7 as well as a service emulator that will send the notification.

The Windows Phone 7 Application

First of all, create a simple Windows Phone 7 application.

I removed all UI content from the main page and left it blank – here I won’t be working with UI and no UI hooks will be present to trigger any specific action. Therefore, the XAML part of my page is pretty simple:

<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>

Then again, this is not the case of a functional application. Now to the functional part.

Push notifications aren’t directly delivered to the phone from a web service, but rather through a ‘proxy’ – the Microsoft Push Notification Service (MPNS). To accept notifications from MPNS, the application must have a channel set up, that would deliver notifications that are bound to it. Each channel has its own unique URI, and this URI is assigned to you by Microsoft.

So the first thing I am going to do is set up a channel – declare a unique instance of HttpNotificationChannel that is a member of the Microsoft.Phone.Notification namespace. Here is what I do during the application initialization:

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);

NOTE: This code is placed inside the App() constructor in App.xaml.cs.

I am opening the channel and explicitly showing that it will be used for toast notifications. As you can see here, I am referencing two additional event handlers – ChannelUriUpdated and ErrorOccured. These event handlers will display a message in the output window, depending on the outcome of the notification channel initialization.

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);
}

The ChannelUriUpdated method is complimentary, but I am using it to find out the URI Micosoft will assign for my application, so I can send notifications to that specific location.

For now, you are pretty much done with the mobile application. Run it and take a peek at the Output dialog. You should see the new assigned URI for the channel, since this is the first time you ever use this application with the specified channel.

Here is what you should get (the URI should be similar to the one shown in the image below):

So you have the channel URI. Now let’s design a WCF service application that will be sending data to the above mentioned channel.

The Service Application

Before creating the application, if you are using Windows 7 or Windows Vista, make sure you launch Visual Studio 2010 as an administrator. Because the application I’m working on will be the host for a service, it will deal with system components that require administrative privileges.

Once started, create a console application. That will be enough to host a simple WCF service.

By default, the application is targeting the .NET Framework 4.0 Client Profile. Since I will be working with WCF, I need to change the target framework to .NET Framework 4.0, in order to access the System.ServiceModel.Web namespace.

Add a reference to System.ServiceModel and System.ServiceModel.Web after you change the target framework. Also, don’t forget about adding using System.ServiceModel and using System.ServiceModel.Web to the class header.

Now, create an interface that will define one base method, that the service will have, that will trigger the notification.

[ServiceContract]
interface IService
{
[OperationContract]
[WebGet]
string SendNotification(string message);
}

The actual class that implements the interface above is this:

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;
}
}

It basically creates a HTTP request to the channel to pass the notification data, that is structured in a XML envelope described here. The headers that are added to the request set the notification type. Once the request is executed, I am returning the notification status, to check whether it was sent or not.

Now in the main application body, I would need to somehow host the service, that will execute the SendNotification method. To do this, I am using an instance of WebServiceHost to specify the location and ServiceEndpoint (member of System.ServiceModel.Description) to specify the endpoint, where the service can be accessed.

WebServiceHost host = new WebServiceHost(typeof(WCFService), new Uri("http://localhost:1234"));
ServiceEndpoint endpoint = host.AddServiceEndpoint(typeof(IService), new WebHttpBinding(), "");
host.Open();

The port selected by me is completely random, so you can specify a different one, as long as it is accessible.

What I want to do here is be able to send notifications as long as the user won’t enter the exit command. Therefore, I am going to use a while loop:

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);

The message is passed to the WCF service via the message parameter, that was defined in the defining interface. By sending a request to the service and by calling the SendNotification method, I am able to pass the message to the MPNS, and that will pass it to the device with the registered channel.

NOTE: To see the notification, the application that has the proper registered channel must not be active.

Here is what you should get at the end:



A common recommendation though, would be not to overuse toast notifications and only pass them when an important event connected to the application occurs, since those are a distraction and eventually a user might become annoyed by them (in case those are passed to often) and block them.

NOTE: You can also call the WCF service from your web browser and the result will be the same.

Article Type: 
How-to
0
The Windows Mobile era has ended, and a totally new and exciting mobile computing platform has emerged—Windows Phone 7.  Finally, a mobile platform has arrived for .NET and Silverlight developers.  Windows Phone 7 has quickly gained a strong following in the mobile developer community.  Even the .NET and Silverlight developers who never developed mobile apps before are now staking a claim in the ever-growing app economy that has resulted from the rise of the smartphone.  The Windows Phone 7 Microzone, which is supported by Microsoft, is your one-stop-shop for tutorials, perspectives, and research on the mobile platform that is making waves in smartphone ecosystem.

Den Delimarsky develops software in the context of the Microsoft stack, enjoying development for Windows (native and using the capabilities of .NET Framework) and Windows Phone 7. He is an active administrator on Dream.In.Code (http://dreamincode.net) where he also hosts a developers' podcast. He is currently pursuing a degree in Computer Science. For more information about his activities you can visit his blog at http://dennisdel.com . Den is a DZone Zone Leader and has posted 341 posts at DZone. You can read more from them at their website.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

James Delpriore replied on Sat, 2010/12/04 - 9:21pm

Hi,

 

I have been going crazy trying to find a good tutorial on this. I cannot get it to connect. Could this be a firewall issue? I get Invalid operation exception was unhandled (channel not open)?

 

Can you please help?

 

Thanks!

//JJ

Rohith Kumar replied on Mon, 2011/12/12 - 6:06am

Hello, I have tried this but it doesnt throw me error nor it shows me the uri..So is it firewall blockage or any other mistake!!!Waiting for ur reply and pls do reply as soon as possible!!! Thanking You!!!

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.