Over the course of this series, we’ve built a SQL Azure database, a Windows Azure worker role, and a WCF web role hosted in Azure. We are fully cloud-enabled at this point! Although, you’ll likely be running this all in the development fabric rather than real Azure until you have a need for enterprise-grade scalability.
Here’s a rough look at what we are working with right now, in a conceptual sense. Explained below the break:
Here’s the diagram explained.
Of course, our device will never receive push notifications if the Azure service doesn’t know about our device, or that we want push notifications. We have to have fields in the database available for the Azure service to, in turn, invoke the Microsoft push notification service. So…
We’ll add one more project to our solution: a Windows Phone 7 Silverlight application. It can be a pivot or a panorama, or a blank app; really it doesn’t matter because we are only going to be working on one screen through the end of this application. I chose to use a Pivot so that you can see on another tab where you might implement the rest of the app (i.e. seeing your stock quotes in one place, for example). Aside from subscribing to push notifications, our app won’t do much, this exercise is just to illustrate what you need to do to subscribe to push notifications.
I marked up MainPage.xaml in Expression Blend to look like the image to the left here.
It’s quite simple – when the user fills in information and clicks Register, their password is hashed and the UserService is called. If the account exists and the password is correct, the data is updated. If the account doesn’t exist, it is created.
The Monitor tab on the right just has a cheeky message like “This is where you’d implement useful stuff that makes the app worth having.” But you might have a nice visual list of stock prices that can be refreshed, or have trends, etc. Those are things you probably know how to do, and is ancillary to the point of this article.
Now that you see how the screen looks, let’s look at how to go about interfacing with these services.
Thankfully, this application only has two external connection points of interest. The first is with the Microsoft push notification service. While we do need to open / find a notification channel to use, we don’t really have to do anything else – no adding of service references or anything like that. It just pretty much works. The other connection point is to the UserService WCF web role we hosted in Azure. We do need to add a service reference here, and we’ll call it asynchronously to register the user’s preferences.
Your main purpose of working with the WCF web role is to register the user and application with the SQL Azure database so that the Microsoft Push Notification Service knows how to get back to the phone to send notifications. We have to add a service reference, which will generate a proxy class which we’ll use to call the RegisterPushReg service operation.
If you right click on the WP7 project’s references and choose Add Service Reference, you’ll get a dialog like the one below. Click the little Discover button to search your solution for services, and choose UserService.
After clicking OK, you’ll be able to use this service. We’ll do that in just a little bit. First, we have to discuss how we are going to tackle the main problem that faces us: how do we get the push notification URI for this device and application?
I did this the easy way. In the PhoneApplicationPage_Loaded event (which I generated in Blend), I make a call to new method called GetPushNotificationURI. I do this asynchronously because I did something I shouldn’t have: I assume that I will get the URI back from the service before the user clicks Register. You know better than that, and will find another way of doing this, or will check for null when you need to use the member pushNotificationUri variable.
private void PhoneApplicationPage_Loaded(object sender, System.Windows.RoutedEventArgs e){ GetPushNotificationURI();}
1: private void GetPushNotificationURI()
2: {
3: string channelName = "AzureStockTestChannel";
4: HttpNotificationChannel channel;
5: channel = HttpNotificationChannel.Find(channelName);
6: if (channel != null)
7: pushNotificationUri = channel.ChannelUri.ToString();
8: else
9: {
10: channel = new HttpNotificationChannel(channelName);
11: channel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(channel_ChannelUriUpdated);
12: channel.Open();
13: channel.BindToShellToast();
14: }
15: }
16:
17: void channel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)
18: {
19: pushNotificationUri = e.ChannelUri.ToString();
20: }
Now that we have the push notification URI, we can send it to the WCF service which will enter it into our SQL Azure database for use by our Azure worker role (phew!)
This is actually the really easy part.
Remember, we created a service reference, so we have this lovely proxy class to work with. (When you finally move this to Azure you will need to configure your service reference with the updated URL).
All of our service methods are called in an asynchronous manner, and they totally should be on a phone – think about the implications of having a blocking service call with no connectivity… yuck! Because of this, we have to subscribe to the _Completed events that are generated in our proxy class.
Here’s the code for the btnRegister_Click event handler:
1: private void btnRegister_Click(object sender, System.Windows.RoutedEventArgs e)
3: UserService.UserServiceClient client = new UserService.UserServiceClient();
4: client.RegisterForPushCompleted += new EventHandler<UserService.RegisterForPushCompletedEventArgs>(client_RegisterForPushCompleted);
5: client.UnregisterForPushCompleted += new EventHandler<UserService.UnregisterForPushCompletedEventArgs>(client_UnregisterForPushCompleted);
6:
7: if (cbUsePushNotifications.IsChecked.Value == true)
8: {
9: client.RegisterForPushAsync(tbUsername.Text, tbStocks.Text, PasswordHash(tbPassword.Text), pushNotificationUri);
10: }
11: else
12: {
13: client.UnregisterForPushAsync(tbUsername.Text, PasswordHash(tbPassword.Text));
Here are the event handlers I implemented for the Completed events (they just show a MessageBox with the results)
1: void client_RegisterForPushCompleted(object sender, UserService.RegisterForPushCompletedEventArgs e)
3: if (e.Result == true)
4: MessageBox.Show("Registered for push notifications");
5: else
6: MessageBox.Show("An error occurred: " + e.Error.ToString());
7: }
8:
9: void client_UnregisterForPushCompleted(object sender, UserService.UnregisterForPushCompletedEventArgs e)
10: {
11: if (e.Result == true)
12: MessageBox.Show("Unregistered for push notifications");
13: else
14: MessageBox.Show("An error occurred: " + e.Error.ToString());
The rest of the code here is rather uninteresting. The only other code that does anything is PasswordHash which generates a SHA1 hash of the user’s password so we are not sending unencrypted passwords over the air:
1: //...
2: using System.Security.Cryptography;
3: //...
4:
5: private string PasswordHash(string input)
6: {
7: HashAlgorithm algorithm = new SHA1Managed();
8: string result = "";
9: using (algorithm)
11: byte[] bytes = Encoding.UTF8.GetBytes(input);
12: result = BitConverter.ToString(algorithm.ComputeHash(bytes));
13: }
14: return result;
We are DONE! In the next post, you’ll see a video recap with a walkthrough of the code and what it looks like when it is all running together.