One Azure Web Role, Multiple Websites

by Brian Hitney 17. January 2012 13:27

Windows Azure has been capable of running multiple websites in a single web role for some time now, but I found myself recently in a situation with 2 separate Azure solutions and was looking to combine them to create a single deployment.   Just like in IIS, this is most often done via host headers, so requests coming in can be forwarded to the correct site.

The Goal

The fine folks at infragistics created a really cool Silverlight-based reporting dashboard for Worldmaps.  Until now, each was running as its own Azure hosted service:

image

Options to consolidate included folding the code into the Worldmaps site, which would involve actual work, or converting the site to use IIS instead of the hostable web core (HWC), which was, originally, the only way to host Azure deployments prior to version 1.3 of the SDK.  Under IIS, host headers can be used to direct traffic to desired correct site.

Preconsiderations

Inside the ServiceDefinition file, the <sites> section is used to define the websites and virtual directories, like so:

<Sites>
<Site name="Web" physicalDirectory="..\WorldmapsSite">
<Bindings>
<Binding name="HttpIn" endpointName="HttpIn" />
</Bindings>
</Site>
<Site name="Reporting" physicalDirectory="..\..\igWorldmaps\WorldmapsDemo.Web">
<Bindings>
<Binding name="HttpIn" endpointName="HttpIn" hostHeader="reporting.myworldmaps.net" />
</Bindings>
</Site>
</Sites>

Nothing too crazy in there, but I’ll talk about the paths later.

The first problem is that I was using webrole.cs file in the Worldmaps application, overriding the Run method to do some background work:

public class WebRole : RoleEntryPoint
{
public override void Run()
{
// I'm doing stuff!
}
}

The Run method is called from a different thread, and it did a lot of background processing for the site (logging data, drawing maps, etc.).   This is a great technique, by the way, to add “workers” to your website.  This is, by itself, not a problem to do under IIS or HWC, except, under the HWC version, the thread runs in the same process.   I could write to an in-memory queue via the website, and process that queue in the webrole.cs without problem, provided the usual thread safety rules are obeyed.  Likewise, the worker could read/write to an in memory cache used by the website.  Under IIS, though, the site and role are in a separate process, so it wasn’t possible to do this without re-engineering things a bit.  You don’t need to worry about this if you aren’t doing anything “shared” in your webrole.cs file.

Add the Project

In my existing Worldmaps solution, I added the infragistics “WorldmapsRporting” project by adding the project to the solution (right click the solution, and choose Add Existing Project):

image

Hook it Up

The <sites> tag (seen above) is pretty self-explanatory as it defines each site in the deployment.  For the first and main site, I didn’t provide a host header because I want it respond to pretty much anything (www, etc.).  For the second site, I give it the reporting.myworldmaps.net host header. 

Here’s the tricky part, which in retrospect seems so straightforward.  The physicalDirectory path is the path to the web project, relative to the Cloud project’s directory.   When I first created the Worldmaps solution (WorldmapsCloudApp4 is when I converted it .NET 4), I had the cloud project, the website itself, and a library project in the same directory, like so, with the cloud project highlighted:

image

So, the path the WorldmapsSite is up one level.  To get to the infragistics website, it’s up to levels, the into the igWorldmaps folder and into the WorldmapsDemo.Web folder.  We can ignore the other folders. 

DNS

The project in Windows Azure is hosted at myworldmaps.cloudapp.net, as seen from the Azure dashboard:

image

…but I own the myworldmaps.net domain.  In my DNS, I add the CNAMEs for both www and reporting, both pointing to the Azure myworldmaps.cloudapp.net URL (picture from my DNS dashboard, which will vary depending on who your DNS provider is):

image

Testing Locally

To test host headers on a local machine, you’d need to add the DNS names to your hosts file (C:\Windows\System32\drivers\etc\hosts) , like so:

127.0.0.1    myworldmaps.net
127.0.0.1    www.myworldmaps.net
127.0.0.1    reporting.myworldmaps.net

Overall, a fairly straightforward and easy way to add existing websites to a single deployment.   It can save money and/or increase reliability by running multiple instances of the deployment.

Links

http://www.myworldmaps.net

http://reporting.myworldmaps.net

Tags: ,

Azure | Tech Tips | USCloud | Worldmaps

Funniest Slide Header I’ve Seen in a Long Time…

by Brian Hitney 6. January 2012 14:10

Credit to a colleague for this slide, but for those who follow Microsoft’s cloud platform might get this reference:

slide

Tags: , ,

Azure | Microsoft

Just One More Week To Enter The Rock Paper Azure Fall Sweepstakes!

by Brian Hitney 12. December 2011 09:40

Week #3 of the Rock Paper Azure Challenge ended at 6pm EST on 12/9/2011. That means another five contestants just won $50 Best Buy gift cards! Congratulations to the following players for having the Top 5 bots for Week #3:

  1. AmpaT
  2. choi
  3. Protist
  4. RockMeister
  5. porterhouse

Just a reminder to folks in the contest, be sure to catch Scott Guthrie, Dave Campbell, and Mark Russinovich live online next Tuesday, 12/13/2011, for the Learn Windows Azure event!

RPAChallenge5

Does your bot have what it takes to win? There is one more week to try and find out, now through December 16th, 2011. Visit the Rock Paper Azure Challenge site to learn more about the contest and get started.

Remember, there are two ways to win:

Sweepstakes

To enter the sweepstakes all you have to do is enter a bot, any bot – even the pre-coded ones we provide – into the game between now and 6 p.m. ET on Dec. 16th. No ninja coding skills need – heck, you don’t even need Visual Studio or a Windows machine to participate!

RPACancun7

At 6 pm ET on Friday, December 16, 2011 the "Fall Sweepstakes" round will be closed and no new entries will be accepted. Shortly thereafter, four bots will be drawn at random for the Grand Prize (trip to Cancun, Mexico), First Prize (Acer Aspire S3 laptop), Second Prize (Windows Phone), and Third Prize (XBox w/Kinect bundle).

RPAPrizesThumbnailsTopHomePage5

Competition

BestBuyGiftCardIcon3For the type-A folks, we’re keen on making this a competitive effort as well, so each week - beginning Nov. 25th and ending Dec. 16th - the top FIVE bots on the leaderboard will win a $50 Best Buy Gift card. If your bot is good enough to be in the top five on successive weeks, you’ll take home a gift card each of those weeks too. Of course, since you’ve entered a bot, you’re automatically in the sweepstakes as well!

Note: As with past iterations of the challenge, even though you can iterate and upload updated bots for the competition, you will only be entered into the sweepstakes one time.

You know what they say… you gotta be in it to win it! Good luck to all players in week #4!

Tags: , , ,

Azure | Events | Microsoft | RPA | USCloud

Music Library Synchronization, Sonos Tips

by Brian Hitney 29. November 2011 18:15

I love Windows Home Server.   I’ve been using Windows Home Server for years, and just purchased a Windows Home Server 2011(WHS) box from Newegg (great deal on a HP Proliant micro server). 

image

Many have asked me why I like WHS so much – it’s NAS, it’s a media server, it’s backup.   It’s a step up from a simple NAS device (although, admittedly, not as plug and play), offers more flexibility and is more cost effective than a Drobo.  A small backup agent can take snapshots of your PC, typically on a daily basis, so they can be restored to a given point in time.  I keep snapshots of my initial installation, for example.  Restoring to those backups is a simple process. 

I’m also a big fan of Sonos, a whole-home music solution that works amazingly well.  What Sonos has done exceedingly well is blend quality hardware, quality software, and reasonable (but not cheap) price points.  I have an extensive music collection, and I point Sonos to a share on my WHS box to index and stream music. 

However, I consider my laptop my “database of record” for my music.  It’s where I download stuff, and I take it with me because I’m often on the road.  The problem I run into is keeping my WHS library in sync with my laptop.   In my case, I want to mirror my library on the WHS exactly as it is on my local collection – and because I’m often reorganizing my collection, adding tags, etc., I need a simple way to do this. 

Enter Robocopy.   Robocopy (Robust file copy) is now built into Windows, and it’s a simple command line tool with a number of options to make this a snap.   For example, if I want to mirror a folder on my laptop with my WHS, this command will do it:

c:\>robocopy "D:\Music" "\\BEAST\Sonos\music" /mir /r:10 /MT:8

D:\Music is my local folder, my server is \\Beast.  The /mir command is for mirror – it’s the same as using /purge and /e:  /purge is to delete files at the target folder that no longer exist in the source, and /e is to copy all subdirectories, including empty ones.   The /r:10 will tell it to retry up to 10 times, in case of some network glitch, and the /MT:8 will have Robocopy use 8 threads to speed things along.   (If you’re familiar with Robocopy, I don’t recommend using /z (restartable) mode as it adds overhead, not needed given the size of files we’re dealing with.)

Now, what if you don’t keep all your music local, and just want to copy it over?   You don’t want to use /mir since it will remove files you otherwise want to keep!   The rest of the command will work fine, but if you move/rename files locally that were previously copied, you’ll have to remember to do that manually on the server.  Once Robocopy does its thing, you’ll get a nice summary:

            Total    Copied   Skipped  Mismatch    FAILED    Extras
Dirs :      1384        29      1355          0         0         0
Files :     15078       381     14697         0         0         0
Bytes : 117.188 g   3.212 g 113.975 g         0         0         0
Times :   0:16:40   0:02:52                       0:00:00   0:00:48

Here, it copied about 30 new folders.  It took about 16 minutes to run, but that’s largely due to new content, having copied some 3.2gb of new files.   Assuming minor changes only, the process typically runs in about 30 seconds.

If you want to get fancy, you could even have Robocopy monitor your folders for changes. 

The next challenge is to have Sonos update its music index once new files are copied over.   Sonos can update its index on a daily basis (or manually via the control software), but I want it done automatically after new files are copied over.  This one is a bit trickier, but thanks to some gurus in the Sonos forums, it’s not impossible.   I’m including the .exe file here for you to use.  Obviously, trusting an exe from someone on the web is not something I’d do, but it’s a .NET assembly which means you can use a tool like JustDecompile to crack it open and look at the source yourself.   Having said that, I’m not responsible if this code causes your computer to blow up, your music collection to vanish, or kills any puppies.

The source code looks like so, and it sends an SOAP packet to a specified Sonos unit to trigger an index rebuild:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;

namespace SonosIndexUpdater
{
class Program
{

static void Main(string[] args)
{
string ip;

if (args != null && args.Length > 0)
{
ip = args[0].Trim();
}
else
{
Console.WriteLine("Missing IP Address. Please add IP address for any Sonos unit.");
return;
}

string header1 = @"SOAPACTION: ""urn:schemas-upnp-org:service
:ContentDirectory:1#RefreshShareIndex"
"";
string postData = @"<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/""
s:encodingStyle="
"http://schemas.xmlsoap.org/soap/encoding/"">
<s:Body>
<u:RefreshShareIndex xmlns:u="
"urn:schemas-upnp-org:service:ContentDirectory:1"">
<AlbumArtistDisplayOption></AlbumArtistDisplayOption></u:RefreshShareIndex>
</s:Body>
</s:Envelope>"
;
string url = string.Format("http://{0}:1400/MediaServer/ContentDirectory/Control", ip);

byte[] byteArray = Encoding.UTF8.GetBytes(postData);

try
{
System.Net.WebRequest req = System.Net.WebRequest.Create(url);
req.Headers.Add(header1);
req.ContentType = "text/xml";
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = byteArray.Length;
req.Timeout = 5000;

Stream dataStream = req.GetRequestStream();

dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();

using (WebResponse response = req.GetResponse())
{
Console.WriteLine("Response from Sonos: {0}",
((HttpWebResponse)response).StatusDescription);

using (dataStream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(dataStream))
{
string responseFromServer = reader.ReadToEnd();
Console.WriteLine("Data: {0}", responseFromServer);
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("Exception occured: {0}", ex.Message);
}

}
}
}
 
To use it, you’d just pass in the IP address of any Sonos unit:
 
c:\>SonosIndexUpdater 192.168.1.100

If you stumbled on this and aren’t a developer but want to try it out, you can build this for free using Visual Studio Express.    Here are some files:
 

EXE file only: Download
VS2010 Solution: Download

Tags: , , ,

Development | Technology | Tech Tips

Azure Camps Coming Soon!

by Brian Hitney 26. November 2011 13:55

Jim, Peter, and I are gearing up for another road trip to spread the goodness that is Windows Azure! The Windows Azure DevCamp series launched recently with a two-day event in Silicon Valley, and we’re jumping on the bandwagon for the East Region.

309b14f7-2f41-49c0-9a50-2c979d9bc97a

We have five stops planned in December, and we’re doing things a bit differently this go-round. Most of the events will begin at 2 p.m. and end at 9 p.m. – with dinner in between of course. The first part will be a traditional presentation format and then we’re bringing back RockPaperAzure for some “hands-on” time during the second half of the event. We’re hoping you can join us the whole time, but if classes or your work schedule get in the way, definitely stop by for the evening hackathon (or vice versa). By the way it wouldn’t be RockPaperAzure without some loot to give away, so stay “Kinected” to our blogs for further details on what’s at stake!

Here’s the event schedule, be sure to register quickly as some venues are very constrained on space. You’ll want to have your very own account to participate, so no time like the present to sign up for the Trial Offer, which will give you plenty of FREE usage of Windows Azure services for the event as well as beyond.

 

Registration Link Date Time
NCSU, Raleigh NC Mon, Dec. 5th, 2011 2 – 9 p.m.
Microsoft, Farmington CT Wed., Dec. 7th, 2011 2 – 9 p.m.
Microsoft, New York City Thur., Dec. 8th, 2011 9 a.m. – 5 p.m.
Microsoft, Malvern PA Mon., Dec. 12th, 2011 2 – 9 p.m.
Microsoft, Chevy Chase MD Wed., Dec. 14th, 2011 2 – 9 p.m.

Tags: , , ,

Azure | USCloud | Technology | Development | Events

Rock, Paper, Azure is back…

by Brian Hitney 22. November 2011 10:24

imageRock, Paper, Azure (RPA) is back!   For those of you who have played before, be sure to get back in the game!  If you haven’t heard of RPA, check out my past posts on the subject.   In short, RPA is a game that we built in Windows Azure.  You build a bot that plays a modified version of rock, paper, scissors on your behalf, and you try to outsmart the competition. 

Over the summer, we ran a Grand Tournament where the first place prize was $5,000!   This time, we’ve decided to change things a bit and do both a competition and a sweepstakes.   The game, of course, is a competition because you’re trying to win.  But we heard from many who didn’t want to get in the game because the competition was a bit fierce.  

Competition:  from Nov 25 through Dec 16, each Friday, we’ll give the top 5 bots a $50 Best Buy gift card.  If you’re the top bot each Friday, you’ll get a $50 gift card each Friday. 

Sweepstakes:  for all bots in the game on Dec 16th, we’ll run the final round and then select a winner at random to win a trip to Cancun.   We’re also giving away an Acer Aspire S3 laptop, a Windows Phone, and an Xbox Kinect bundle.  Perfect timing for the holidays!

Rock Paper Azure

Check it out at http://www.rockpaperazure.com!

Tags: , , ,

Azure | Development | USCloud | RPA

Geo-Load Balancing with the Azure Traffic Manager

by Brian Hitney 10. October 2011 14:18

One of the great new features of the Windows Azure platform is the Azure Traffic Manager, a geo load balancer and durability solution for your cloud solutions.  For any large website, managing traffic globally is critical to the architecture for both disaster recovery and load balancing.

When you deploy a typical web role in Azure, each instance is automatically load balanced at the datacenter level.   The Azure Fabric Controller manages upgrades and maintenance of those instances to ensure uptime.  But what about if you want to have a web solution closer to where your users are?  Or automatically direct traffic to a location in the event of an outage?   

This is where the Azure Traffic Manager comes in, and I have to say, it is so easy to set up – it boggles my mind that in today’s day and age, individuals can prop up large, redundant, durable, distributed applications in seconds that would rival the infrastructure of the largest websites. 

From within the Azure portal, the first step is to click the Virtual Network menu item.

image

On the Virtual Network page, we can set up a number of things, including the Traffic Manager.   Essentially the goal of the first step is to define what Azure deployments we’d like add to our policy, what type of load balancing we’ll use, and finally a DNS entry that we’ll use as a CNAME:

image

We can route traffic for performance (best response time based on where user is located), failover (traffic sent to primary and only to secondary/tertiary if primary is offline), and round robin (traffic is equally distributed).   In all cases, the traffic manager monitors endpoints and will not send traffic to endpoints that are offline.

I had someone ask me why you’d use round robin over routing based on performance – there’s one big case where that may be desirable:  if your users are very geography centric (or inclined to hit your site at a specific time) you’d likely see patterns here one deployment gets maxed out, while another does not.   To ease the traffic spikes to one deployment, round robin would be the way to go.  Of course, an even better solution is to combine traffic shaping based on performance with Azure scaling to meet demand.

In the above image, let’s say I want to create a failover for the Rock Paper Azure botlab (a fairly silly example, but it works).   I first added my main botlab (deployed to South Central) to the DNS names, and then added my instance deployed to North Central:

image 

From the bottom of the larger image above, you can see I’m picking a DNS name of botlab.ctp.trafficmgr.com as the public URL.  What I’d typically do at this point is go in to my DNS records, and add a CNAME, such as “www.rockpaperazure.com” –> “rps.ctp.trafficmgr.com”.

In my case, I want this to be a failover policy, so users only get sent to my North Central datacenter in the event the south central instance is offline.  To simulate that, I took my south central instance offline, and from the Traffic Manager policy report, you’d see something like this:

image

To test, we’ll fetch the main page in IE:

image

… and we’re served from North Central.  Of course, the user doesn’t know (short of a traceroute) where they are going, and that’s the general idea.  There’s nothing stopping you from deploying completely different instances except of course for the potential end-user confusion!

But what about database synchronization?   That’s a topic for another post …

Tags: , , ,

Azure | Development | USCloud | Technology

CodeMastery This Weekend in Atlanta

by Brian Hitney 5. October 2011 10:55

Chris Williams just let me know about an event happening in Atlanta this Saturday, Oct 8 … and it’s free!  Free is good.   Check it out here:

http://codemastery.eventbrite.com/

Sessions:

1. CSLA .NET intro - Rocky Lhotka

Topic will give attendees a high level overview of CSLA as an application framework. Key moving parts of CSLA will be covered, along with answering the most important question: Why use CSLA? Roles of business objects, data portal, rules, authentication and authorization will be covered in principal.

2. Business object design - Eric Blackwell

Session will concentrate of best practices for designing business objects. Single responsibility principal and maintainability will be covered in light of using CSLA. Key aspects of good CSLA business layer will be covered in detail, including properties, rules, data portal, data access, business method and validation. Particular attention will be paid to structuring classes and relationship between classes. Designing based on use cases will be an important aspect of the session.

3. Business, validation, and authorization rules - Tim Price-Williams

This session will be a deep dive into the world or rules. Topics such as validation rules, user authentication and authorization will be covered. Distinction between validation and business rules be drawn. Important key scenarios will be covered, such as synchronous and asynchronous rules, client / server rules, object creation and save scenario from rules perspective. Custom and built-in rules be covered in detail. A pattern for typical business rule/methods will be illuminated.

4. Data portal and n-tier architecture - Rocky Lhotka

This topic will cover in details all possibilities that CSLA provides when abstracting communication channels between client and server components. Difference between local and remote data portal will be discussed. Various configuration patterns will be highlighted along with usage scenarios for each one. Multi-tier deployment as it relates to data portals will be covered, as well as using external data sources instead of CSLA data portal in client only scenarios.

5. Data access - Travis Brown

This session is all about data access technologies and how they relate to CSLA data portal access. The topic will include patterns for abstracting data access for business objects to promote maintainability. Discussion of Microsoft technologies for data access will take place as well.

6. XAML and MVVM - Sergey Barskiy

This session will concentrate on using CSLA as business layer in XAML based user interfaces. Taking Silverlight as an example, session will highlight how CSLA base classes can be used to facilitate communication between UI and business objects. Adaptability of CSLA business layer to seamlessly alter user interface based on rules be will covered. Patterns for wiring business objects for Silverlight environment will be part of the discussion.

7. ASP.NET MVC - Mitch Gordon

This session will concentrate on using CSLA as business layer in ASP.NET MVC based user interfaces. The discussion will include CSLA provided base classes that will allow developers write less code. The session will illuminate patters for maintaining authentication and authorization rules between server calls. Patterns for adapting UI based on user rights will be discussed.

Tags: ,

Events | Development

Use the Windows Azure CDN for Assets

by Brian Hitney 26. September 2011 19:28

The most common response to running stuff in the cloud (Azure, Amazon in particular) is the that it’s too expensive for the little guy.   And generally, hosting VMs when a small shared site of something similar will suffice is a tough argument.

There are aspects to Azure, though, that are very cost effective as they do “micro-scale” very well.  A good example of this is the Azure CDN, or more simply, Azure Blob Storage.   It’s effective to exchange files, it’s effective at fast delivery, and even lightweight security using shared access signatures (links that essentially only work for a period of time).    It’s durable:  not just redundant internally, but externally as well, automatically creating a backup in another datacenter.

For MSDN subscribers, you already have Azure benefits, but even going out of pocket on Blob storage isn’t likely to set you back much:  $0.15/GB of storage per month, $0.01/10,000 transactions, and $0.15/GB outbound bandwidth ($0.20 in Asia; all inbound free).  A transaction is essentially a “hit” on a resource, so each time someone downloads, say, an image file, it’s bandwidth + 1 transaction. 

Because these are micro transactions, for small apps, personal use, etc., it’s quite economical … often adding up to pennies per month.   A few typical examples are using storage to host files for a website, serve content to mobile devices, and to simply offload resources (images/JS files) from website code.

Depending on usage, the Azure Content Delivery Network (CDN) can be a great way to enhance the user experience.  It may not always be the case (and I’ll explain why) but essentially, the CDN has dozens of edge servers around the world.  While your storage account is served from a single datacenter, having the data on the edge servers greatly enhances speed.   Suppose an app on a phone is retrieving documents/text to a worldwide audience … enabling CDN puts the content much closer. 

I created a test storage account in North Europe (one of the Azure datacenters) to test this, using a small graphic from RPA:  http://somedemoaccount.blob.core.windows.net/images/dicelogo.png

Here’s the same element via the CDN (we could be using custom DNS names, but for demo purposes we’re not): http://az32338.vo.msecnd.net/images/dicelogo.png

Here’s a trace to the storage account in the datacenter – from North Carolina, really not that bad all things considered:

image

You can see we’re routed to NY, then on across the pond, and total latency of about 116ms.   And now the CDN:

image

MUCH faster, chosen not only by physical distance but also network congestion.   Of course, I won’t see a 100ms difference between the two, but if you’re serving up large documents/images, multiple images, or streaming content, the difference will be noticeable. 

imageIf you’re new to Azure and have an account, creating a storage account from the dashboard is easy.   You’d just click on your storage accounts, and enter a name/location:

image

You’d typically pick someplace close to you or where most of your users are.   To enable CDN, you’d just click the CDN link on the left nav, and enable it:

image

Once complete, you’ll see if on the main account screen with the HTTP endpoint:

image

So why wouldn’t you do this?

Well, it’s all about cacheability.   If an asset is frequently changing or infrequently used, it’s not a good candidate for caching.   If there is a cache miss at a CDN endpoint, the CDN will retrieve the asset from the base storage account.  This will incur an additional transaction, but more importantly it’s slower than if the user just went straight to the storage account.  So depending on usage, it may or may not be beneficial. 

Tags: , , ,

Azure | USCloud | Tech Tips

Azure and Phone … Better Together

by Brian Hitney 21. September 2011 17:58

We had an excellent time presenting today’s Windows Phone Camp in Charlotte. Thank you to everyone who attended. Here are some resources and major points of today’s “To the cloud…” session.

First, here is the slide deck for the presentation. 

Next, download the Windows Azure Toolkit for Windows Phone. This contains both the sending notifications sample, and the Babelcam application. Note that there are quite a few setup steps – using the Web Platform Installer is a great way to make all of this easier.

The key takeaway that I really wanted to convey: while the cloud is most often demonstrating massive scale scenarios, it’s also incredibly efficient at micro scale. The first scenario we looked at was using Azure Blob Storage as a simple (yet robust) way to host assets. Think of Blob Storage as a scalable file system with optional built in CDN support. Regardless of where your applications of hosted (shared host, dedicated hosting, or your own datacenter), and regardless of the type of application (client, phone, web, etc.) the CDN offers a tremendously valuable way to distribute those resources.

For MSDN subscribers, you already have access so there’s no excuse to not use this benefit. But even if you had to go out of pocket, hosting assets in Azure is $0.15/GB per month, + $0.01/10,000 transactions, + $0.15/GB outbound bandwidth (inbound is free). For small applications, it’s almost free. Obviously you need to do the math for your app, but consider hosting 200MB in assets (images, JS files, XAPs, etc.), a million transactions a month with several GB of data transfers: it’s very economical at the cost of a few dollars / month.

In the second demo, we looked at using Azure Queues to enhance the push notification service on the phone. The idea being that we’ll queue failed notifications, and retry them for some specified period of time. For the demo, I only modified the raw notifications. In PushNotificationsController.cs (in toolkit demo above), I modified SendMicrosoftRaw slightly:

[HttpPost]
public ActionResult SendMicrosoftRaw(string userId, string message)
{
if (string.IsNullOrWhiteSpace(message))
{
return this.Json("The notification message cannot be null, empty nor white space.",
JsonRequestBehavior.AllowGet);
}

var resultList = new List<MessageSendResultLight>();
var uris = this.pushUserEndpointsRepository.GetPushUsersByName(userId).Select(u => u.ChannelUri);
var pushUserEndpoint = this.pushUserEndpointsRepository.GetPushUsersByName(userId).FirstOrDefault();

var raw = new RawPushNotificationMessage
{
SendPriority = MessageSendPriority.High,
RawData = Encoding.UTF8.GetBytes(message)
};

foreach (var uri in uris)
{
var messageResult = raw.SendAndHandleErrors(new Uri(uri));
resultList.Add(messageResult);

if (messageResult.Status.Equals(MessageSendResultLight.Error))
{
this.QueueError(pushUserEndpoint, message);
}
}

return this.Json(resultList, JsonRequestBehavior.AllowGet);
}

Really the only major change is that if the messageResult comes back with an error, we’ll log the error. QueueError looks like this:

private void QueueError(PushUserEndpoint pushUser, string message)
{
var queue = this.cloudQueueClient.GetQueueReference("notificationerror");

queue.CreateIfNotExist();
queue.AddMessage(new CloudQueueMessage(
string.Format("{0}|{1}", pushUser.ChannelUri.ToString(), message)
));
}

We’re simply placing the message on the queue with the data we want: you need to get used to string parsing with queues. In this case, we’ll delimit the data (which is the channel URI and the message of the notification) with a pipe character. While the channel URI is not likely to change, it’s a better approach to store the username and not the URI in the message, and instead do a lookup of the current URI before sending (much like the top of SendMicrosoftRaw does), but for the purposes of the demo is fine.

When we try sending a raw notification when the application isn’t running, we’ll get the following error:

image_thumb3

Typically, without a queue, you’re stuck. Using a tool like Cloud Storage Studio, we can see the notification is written to the failure queue, including the channel URI and the message:

image_thumb5

So, now we need a simple mechanism to poll for messages in the queue, and try to send them again. Because this is an Azure webrole, there’s a way to get a “free” thread to do some processing. I say free because it’s invoked by the Azure runtime automatically, so it’s a perfect place to do some background processing outside of the main site. In Webrole.cs, you’ll see there is no Run() method. The base WebRole Run() method does nothing (it does an indefinite sleep), but we can override that. The caveat is, we never want to exit this method. If an exception bubbles out of this method, or we forget to loop, the role will recycle when the method exits:

public override void Run()
{
this.cloudQueueClient = cloudQueueClient ??
GetStorageAccountFromConfigurationSetting().CreateCloudQueueClient();
var queue = this.cloudQueueClient.GetQueueReference("notificationerror");
queue.CreateIfNotExist();

while (true)
{
Thread.Sleep(200);

CloudQueueMessage message = queue.GetMessage(TimeSpan.FromSeconds(60));

if (message == null) continue;

if (message.DequeueCount > 60)
{
queue.DeleteMessage(message);
continue;
}

string[] messageParameters = message.AsString.Split('|');

var raw = new RawPushNotificationMessage
{
SendPriority = MessageSendPriority.High,
RawData = Encoding.UTF8.GetBytes(messageParameters[1])
};

var messageResult = raw.SendAndHandleErrors(new Uri(messageParameters[0]));

if (messageResult.Status.Equals(MessageSendResultLight.Success))
{
queue.DeleteMessage(message);
}
}
}

What this code is doing, every 200 milliseconds, is looking for a message on the failure queue. Messages are marked with a 60 second timeout – this will act as our “retry” window. Also, if we’ve tried to send the message more than 60 times, we’ll quit trying. Got to stop somewhere, right?
 
We’ll then grab the message from the queue, and parse it based on the pipe character we put in there. We’ll then send another raw notification to that channel URI. If the message was sent successfully, we’ll delete the message. Otherwise, do nothing and it will reappear in 60 seconds.
 
While this code is running in an Azure Web Role, it’s just as easy to run in a client app, service app, or anything else. Pretty straightforward, right? No database calls, stored procedures, locking or flags to update. Download the completed project (which is the base solution in the toolkit plus these changes) here (note: you’ll still need the toolkit): 

The final demo was putting it all together using the Babelcam demo – Azure queues, tables, notifications, and ACS.

Questions or comments? Let me know.

Tags: , , ,

Azure | Windows Phone 7 | USCloud | Events

your host...

Brian Hitney
Developer Evangelist
Microsoft Corp.

About Me

My Worldmap