Using Cloud Services to send Notifications with Windows Phone

I am pretty excited because this week one of my other personal side projects called the “Windows Phone Baby Monitor” just won that “2012 Appies People’s Choice Award”, an internal contest for Microsoft colleagues. What I would like to do in this post is give you some background on how I managed to implement SMS, Phone and Email notifications from Windows Phone for this app.

baby_monitor-191x300

Background

This application basically turns your Windows Phone into a baby monitor. You leave the phone near your baby while it is sleeping and then when it detects crying it will send a notification by phone, email or SMS. There are a number of things that I do within the application to set the decibel level and length of time the crying lasts to avoid false notifications like doors slamming.

Sending Notifications with Windows Phone API’s

When I first started building the application, I figured this would be very simple to implement because I could just write to some sort of Windows Phone API that would allow me to send the SMS, email or phone notifications. Although there is an API for doing this, the main issue I had was the fact that the user needed to physically click an approve button for the notification to complete. Since I figured it was somewhat unrealistic to expect a baby to sit up, move to the phone and click a button when it was done sleeping, I needed to come up with another solution.

Using Services to Send Notifications

From my work with Cotega (which is a monitoring service for SQL Azure databases), I had a little background experience on how to send notification. For that service, I used Amazon’s SES to send email notifications. For this Baby Monitor, I chose to use a different service called SendGrid to send email notifications. I used this service over Amazon SES because I wanted to compare the two and also because there was a great offer of 25,000 free emails / month for Azure services. Since SendGrid does not support sending SMS or making phone calls, for this part I chose to use Twilio.

SendGrid

SendGrid was incredibly easy to implement within my MVC service. The way it works with the Baby Monitor is that when the phone detects crying, it makes a WebClient request to my MVC service, passing some details like the Windows Phone device id, decibel level and the email address that needs to be contacted. From that point the service makes a SendGrid request to send the email. As you can see, the controller code is pretty simple and looks like this.

using SendGridMail;
using SendGridMail.Transport;

// Create the email object first, then add the properties.
SendGrid myMessage = SendGrid.GenerateInstance();
myMessage.AddTo(emailAddress);
myMessage.From = new MailAddress("\"Cotega Baby Monitor\" ", "Cotega Baby Monitor");
myMessage.Subject = "Baby Monitor Alert!";
myMessage.Text = "Crying was detected by the Baby Monitor.  Decibel Level: " + maxDecibels + ".  ";
 
// Create credentials, specifying your user name and password.
var credentials = new NetworkCredential("[myusername]", "[MyPassword]");
 
// Create an REST transport for sending email.
var transportREST = REST.GetInstance(credentials);
 
// Send the email.
transportREST.Deliver(myMessage);

Twilio for Sending SMS and Phone Notifications

This part was a little more complex because although sending notifications through Twilio is pretty cheap within North America, I still needed a mechanism to limit the ability for people to send unlimited notifications. For this, I chose to implement a token based system that was linked to the device id of the phone. When they download the app, I give them a certain number of tokens to send SMS and make phone calls (emails are free), and if they wish to purchase more they can do so and tokens are applied to their account. There are some really cool things about Twilio such as:

  • Text to Voice for phone calls: This allows me to send some text to the Twilio service such as “Your baby is crying” and when Twilio makes a call to the the person’s phone, the person hear’s a computer like voice stating “Your baby is crying”.
  • Attaching audio files to phone calls: When I call the Twilio service, I can pass it a link to a URL that contains an audio file. When Twilio makes the call to the person, the audio file can be played over the phone. This is really useful because I can attach a snippet of audio of their baby crying to allow them to ensure that it is really their baby crying and not a jack hammer in the background or something else.

Just like SendGrid, the code used in the MVC controller is really very simple using the TwitML api. Here is what it looks like for sending SMS messages.

using Twilio;
using Twilio.TwiML;
?
1
2
3
//twilioAccountSID and twilioAuthToken values are store in the web.config (hopefully encrypted)
public string twilioAccountSID = ConfigurationManager.AppSettings["twilioAccountSID"];
public string twilioAuthToken = ConfigurationManager.AppSettings["twilioAuthToken"];

//This it the controller code that sends the SMS message

var twilio = new TwilioRestClient(twilioAccountSID, twilioAuthToken);
string smsMessageBody = "Baby Monitor Alert! Crying detected at decibel Level: " + maxDecibels + ". ";
if (fileName != null)
smsMessageBody += "http://cotega.com/audio/" + fileName + ".wav";
// if phone number is 10 digits I need to add the +1
if (phoneNumber.Length == 10)
phoneNumber = "+1" + phoneNumber;
var msg = twilio.SendSmsMessage("+1[mytwilionumber]", phoneNumber, smsMessageBody);

There is a little bit of code that I have not show before and after that first checks a SQL Azure database to see if they have enough tokens to send a notification, and then updates their token count after the message is sent.

The code for making the phone call is very similar.

// Create an instance of the Twilio client.TwilioRestClient client;client = newTwilioRestClient(twilioAccountSID, twilioAuthToken);// Use the Twilio-provided site for the TwiML response.String Url = "http://twimlets.com/message";Url = Url + "?Message%5B0%5D="+ "Hello.%20Crying%20was%20detected%20by%20the%20baby%20monitor.";if(fileName != null)Url += "&Message%5B1%5D="+ "http://www.cotega.com/audio/"+fileName+".wav";// Instantiate the call options that are passed to the outbound callCallOptions options = newCallOptions();// Set the call From, To, and URL values to use for the call.// This sample uses the sandbox number provided by// Twilio to make the call.options.From = "+1[my twilio number]";options.To = "+1"+ phoneNumber;options.Url = Url;// Make the call.Call call = client.InitiateOutboundCall(options);

Notice how I can attach a string of text along with a url to http://twimlets.com/message. For example, try clicking this link and see the XML that is created. If you passed this to Twilio it would make a phone call and say “Hello from Liam”. Notice also, how I attached a link to a WAV file. Twilio will take that audio and play it when the person answers the phone. Very cool right?

As I mentioned, I did not go into many details of how I linked the Windows Phone device ID to the service to allow me to verify they have enough tokens before making the call, but if you are interested in this, let me know and I can help you get going.

Liam

How to use PayPal with ASP.NET MVC

I talked previously about why I chose to use Stripe with Cotega to allow me to accept credit card payments. In it I talked about how excellent their support was and how easy it was to take their samples and implement it into my service. I am still extremely pleased with my choice of using Stripe and I have no intention of moving away from it. I have however always wanted to investigate using PayPal as an alternative payment option because occasionally International customers will have credit cards that are not acceptable by Stripe or they just plain prefer to use PayPal. For this reason, I decided to take some time and understand what it would take to implement PayPal into my MVC based service.
Unfortunately, I did not find this to be quite as simple to implement as it was with Stripe. Although PayPal has a number of examples, none of the ones I could find were targeted for MVC and there did not seem to be any good tutorials on this subject to get me started. I hope this blog post will help anyone thinking to implement PayPal with MVC. I do want to caveat this with the fact that I am far from a PayPal expert and I do not claim that this is the “PayPal preferred” way to implement this other than to say that I have tried to convert other examples as best I can and it has worked well for me so far. If you have any comments or suggestions, I am very interested to hear your feedback.

Step 1 – Choosing PayPal IPN vs. PDT vs. Express

One of the first things I needed to decide on was the appropriate “PayPal Responder” to use. A responder is like a callback that PayPal does when the transaction is complete (successful, unsuccessful, invalid, etc.). It can also return custom variables that you set when the user first clicks the “Pay Now” button.
Since we are using MVC, we first need to create a View that initiates the transaction to PayPal. This is where the user clicks the “Pay Now” button and is re-directed to PayPal where they enter their credit card or PayPal account information. After this is complete, PayPal can initiate a responder which calls your service with the results of the transaction. The flow of the process looks something like this:

paypal_payment_process

You really only need to use a responder in the cases where you need to continue with some process after that transaction completes. For example, in my case I want to be able to enable a user subscription once the transaction completes. If you are simply accepting payments, there may be no need to go to the complexity of using responders.
There is lots of information on responders but I found that Instant Payment Notifications (IPN) was the best choice for me, and probably yourself as well if you simply want a callback from PayPal to your MVC controllers.

Step 2 – Implementing the View and Form

The next step is to create a payment page using a View where the user can choose to start the PayPal process. Here is an example of a HTML form that I used.

There are a couple of things you should notice in this form:

  • The commented out section allows me to either submit the payment request to the PayPal sandbox (test) environment or to the actual live PayPal url.
  • Notice all the input type=”text” types. These are values that are returned to my controller after the transaction is complete. When I load the page, I set the “device-id” input type to a custom value that I want PayPal to return when the transaction completes. I can use this value to update the user’s status in my SQL database (assuming the transaction is successful).
  • The “return” input type URL defines where the user will be redirected to after the transaction is complete. It is important that you don’t rely on this as a method for completing a transaction because most users will never click on this link. Don’t forget to create this page.
  • The notify_url input is the IPN URL that PayPal will call after the transaction completes.
  • Remember to associate the business input type email address with the PayPal address you used for your sandbox or live account
  • There are a lot more custom values you can use and learn more about here.

Step 3 – Creating an IPN Controller in MVC

Next we will want to create a new ActionResult controller that will receive the responder request from PayPal after the transaction completes. I want to give credit to this page where I was able to leverage a lot of code for this controller. You should also remember to actually create an IPN view (IPN.cshtml) page because PayPal will continue to call this controller until it gets a successful page returned.

public ActionResult IPN() { // Receive IPN request from PayPal and parse all the variables returned var formVals = new Dictionary(); formVals.Add("cmd", "_notify-validate"); // if you want to use the PayPal sandbox change this from false to true string response = GetPayPalResponse(formVals, false); if (response == "VERIFIED") { string transactionID = Request["txn_id"]; string sAmountPaid = Request["mc_gross"]; string deviceID = Request["custom"]; //validate the order Decimal amountPaid = 0; Decimal.TryParse(sAmountPaid, out amountPaid); if (sAmountPaid == "2.95") { // take the information returned and store this into a subscription table // this is where you would update your database with the details of the tran return View(); } else { // let fail - this is the IPN so there is no viewer // you may want to log something here } } return View(); } string GetPayPalResponse(DictionaryformVals, bool useSandbox) { // Parse the variables // Choose whether to use sandbox or live environment string paypalUrl = useSandbox ? "https://www.sandbox.paypal.com/cgi-bin/webscr" : "https://www.paypal.com/cgi-bin/webscr"; HttpWebRequest req = (HttpWebRequest)WebRequest.Create(paypalUrl); // Set values for the request back req.Method = "POST"; req.ContentType = "application/x-www-form-urlencoded"; byte[] param = Request.BinaryRead(Request.ContentLength); string strRequest = Encoding.ASCII.GetString(param); StringBuilder sb = new StringBuilder(); sb.Append(strRequest); foreach (string key in formVals.Keys) { sb.AppendFormat("&{0}={1}", key, formVals[key]); } strRequest += sb.ToString(); req.ContentLength = strRequest.Length; //for proxy //WebProxy proxy = new WebProxy(new Uri("http://urlort#"); //req.Proxy = proxy; //Send the request to PayPal and get the response string response = ""; using (StreamWriter streamOut = new StreamWriter(req.GetRequestStream(), System.Text.Encoding.ASCII)) { streamOut.Write(strRequest); streamOut.Close(); using (StreamReader streamIn = new StreamReader(req.GetResponse().GetResponseStream())) { response = streamIn.ReadToEnd(); } } return response; }

Step 4 – Enabling Sandbox and IPN

I highly recommend that you first test this with the PayPal sandbox. You need to sign up separately for a sandbox account from your live PayPal account from the developer page here.
For sandbox accounts, you do not need to enable IPN, but for live accounts you do. Once you are ready to switch to live, log in to your PayPal account and go to Profile | More Options | My Selling Tools | Choose Update for “Instant Payment Notifications” and then enable IPN and set the URL that you wish PayPal to call (which is the IPN controller we created above).

Summary

At this point you should be ready to go. One of the real pains of this system is that there is no easy way to debug your IPN controller if you are running the MVC app on a remote machine that does not have Visual Studio installed. For this reason, I chose to log each of the steps to a “Log” table that I created in my database. That way I could log all the variables that PayPal returned and still get an idea of what was happening or determine if there were any issues.
I am still testing this and have not yet implemented this into my Cotega service for monitoring SQL Azure databases. For now, if you would like to see this working I am using it in a Windows Phone Baby Monitor app that I wrote.
If you have any suggestions or problems I look forward to hearing from you.