In the last post, we learned how to write an Azure worker role to poll stocks from the Yahoo! Finance service for a particular user and send them a push notification. It works, trust me; it’s just that we have no way of knowing because there is no data in your database. Only your phone / emulator knows the push notification URI that is unique to that combination of phone and app, so it’s the phone’s job to tell our system what exactly that is.
To make that possible, we’ve created a WCF Web Role which will expose an endpoint to the greater Internets™. This way, your phone will always have a way of registering with our service, as long as it has a data connection. We’ll be running and testing this on our local machines, but it’s just as easy to move it to the real world because all you need to do is change a configuration setting in the phone app.
This article focuses on the PushRegService WCF Web Role we created when we set up the Azure solution, so go ahead and open that project now.
1: using System.Runtime.Serialization;
2: using System.ServiceModel;
3:
4: namespace PushRegService
5: {
6: [ServiceContract]
7: public interface IUserService
8: {
9: [OperationContract]
10: bool RegisterForPush(string username, string keywords, string passwordHash, string pushNotificationURI);
11:
12: [OperationContract]
13: bool UnregisterForPush(string username, string passwordHash);
14:
15: [OperationContract]
16: bool CreateNewUser(string username, string passwordHash, string alertKeywords);
17: }
18:
19:
20: // Use a data contract as illustrated in the sample below to add composite types to service operations.
21: [DataContract]
22: public class UserData
23: {
24: [DataMember]
25: public int UserID { get; set; }
26:
27: [DataMember]
28: public string Username { get; set; }
29:
30: [DataMember]
31: public string PushNotificationURI { get; set; }
32:
33: [DataMember]
34: public string AlertKeywords { get; set; }
35:
36: [DataMember]
37: public bool UsePushNotifications { get; set; }
38:
39: [DataMember]
40: public string PasswordHash { get; set; }
41: }
42: }
I’ve chosen to do this in as bare-bones a manner as possible, mainly so that we can just see this whole mess working together as quickly as possible. In the real world, you’d have an elaborate user account system, where you have an interface to create a new account, then verify the email, then log-in, etc. We don’t have the time or the space on this blog to do all that () so, instead, we’re just going to do it all-at-once. What that means is that the user will be presented (in the WP7 app) with a single screen that has fields for user, password, stocks to watch and whether or not to receive notifications. When the user hits Register, it will hit the service. If the account doesn’t exist, we’ll create one and set those preferences. If the account does exist, we log in with the provided password and update the existing fields.
The first thing we’ll do is implement the RegisterForPush method, since that’s all we are really going to test at this time. In code you can’t see, the UserService class is marked with a ServiceBehavior attribute that allows exceptions to pass through (IncludeExceptionDetailsInFaults = true). This makes debugging WCF services a lot easier especially when you are debugging them by way of a WP7 application.
1: public bool RegisterForPush(string username, string keywords, string passwordHash, string pushNotificationUri)
2: {
3: try
4: {
5: AzureAlertsEntities entities = new AzureAlertsEntities();
6:
7: // determine if a new account needs to be created
8: if (entities.Users.Count(u => u.Username == username) == 0)
9: {
10: // create a new user
11: entities.AddToUsers(new User()
12: {
13: AlertKeywords = keywords,
14: PasswordHash = passwordHash,
15: Username = username,
16: UsePushNotifications = true,
17: PushNotificationURI = pushNotificationUri
18: });
19: entities.SaveChanges();
20: return true;
21: }
22: else
24: // find the existing user and update
25: if (entities.Users.Count(u => u.Username == username && u.PasswordHash == passwordHash) == 0)
26: {
27: // if no matches, then the login is wrong
28: throw new Exception("The username or password is incorrect.");
29: }
30:
31: // otherwise, just update
32: User user = entities.Users.Where(u => u.Username == username && u.PasswordHash == passwordHash).Single();
33: user.PushNotificationURI = pushNotificationUri;
34: user.UsePushNotifications = true;
35: entities.SaveChanges();
36: return true;
37: }
38: }
39:
40: catch(Exception ex)
41: {
42: throw ex;
43: }
44: }
45:
Line 5 declares our Entity Framework instance that allows easy access to the database.
First we check to see if the user exists; if not, we create a new user. Then, we check the password, which is hashed with SHA1. If they don’t match, we throw an exception. If they do, we set that user’s preferences and save the changes. Congratulations! We’ve successfully registered a user for push notifications.
Here is the full code for the User Service:
using System;
using System.Linq;
using System.ServiceModel;
using Utilities.ORM;
namespace PushRegService
{
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class UserService : IUserService
public bool CreateNewUser(string username, string passwordHash, string alertKeywords)
try
AzureAlertsEntities entities = new AzureAlertsEntities();
User newUser = new User()
Username = username,
PasswordHash = passwordHash,
AlertKeywords = alertKeywords,
UsePushNotifications = false,
PushNotificationURI = ""
};
entities.AddToUsers(newUser);
entities.SaveChanges();
return true;
}
catch
return false;
public bool UnregisterForPush(string username, string passwordHash)
// determine if a new user needs to be created
if (entities.Users.Count(u => u.Username == username) == 0)
// create a new user
entities.AddToUsers(new User()
AlertKeywords = "",
});
else
// find the existing user and update
if (entities.Users.Count(u => u.Username == username && u.PasswordHash == passwordHash) == 0)
// if no matches, then the login is wrong
throw new Exception("The username or password is incorrect.");
// otherwise, just update
User user = entities.Users.Where(u => u.Username == username && u.PasswordHash == passwordHash).Single();
user.PushNotificationURI = "";
user.UsePushNotifications = false;
catch(Exception ex)
throw ex;
public bool RegisterForPush(string username, string keywords, string passwordHash, string pushNotificationUri)
// determine if a new account needs to be created
AlertKeywords = keywords,
UsePushNotifications = true,
PushNotificationURI = pushNotificationUri
user.PushNotificationURI = pushNotificationUri;
user.UsePushNotifications = true;
UserService.svc.cs
You’ll notice one of the arguments to this operation is the push notification URI. This URI is generated when the phone attempts to subscribe to a notification channel (more on that later). That just means that we get this value from code magic, and store it in the database for use later, kind of like you would with an OAuth access token. We don’t care what exactly it is, just that we have it; it’s the “key.” Once we have our push notification URI stored in a database and associated to a user’s record, we can send them push notifications whenever we like.
One final note for this post is that you must inform the user that push notifications are being used in the app and give them an option to decline receiving them. If you want your app to pass certification, that is.
Up next, we’ll talk about building the Windows Phone mini-app itself, followed by a wrap-up post. We’re almost there!