One of my most frequent issues when releasing to Azure websites using the old build system from VSTS/VSO is the deployment fails. By old build system, I mean the continuous deployment magic you set up from the Azure portal for an Azure website (now App Service). The worst is on a good sized solution I work on which takes about 20 minutes to build. So I wait the 20 minutes, only for it to fail for reasons beyond my control on the deployment step with errors like "invalid thumbprint" or "intermittent communications issues." Despite the build succeeding, I'm left kicking a new build and waiting 20 minutes just for the deployment. So I was really excited to see the new Build and Release Management system in VSTS/VSO where it looks that option is possible, retrying just that deployment step. On the solution with the 20 minute build time, there are also four different configurations. (This means there's potentially 80 minutes of wasted build time if the deploy fails for all.) The new build and release system also looks to have a multi-configuration option where I can build all four at once.

So diving into the main getting started tutorial, it looks very promising. First thing is to set up the build. I'm following the tutorial exactly as shown by creating a Visual Studio build, but with three small additional steps in order to cope with building all four of my configurations. On the variables tab, I replaced the existing build configuration values with my four configurations, separating each with a comma. If you save and queue a build at this point, it will fail, as it treats the value as a single configuration.

The next piece for multiple configurations is on the Options tab. (This has changed, see edit under the image below.) Put a check next to MultiConfiguration, and set Multipliers to "BuildConfiguration". You can optionally choose to check the options below, as I have, to potentially build in parallel and continue with other build configurations if one fails.

*Edit 2018-02-01: Microsoft moved this when multi-phase builds released. This can be enabled now in the Tasks tab by selecting the Phase. I believe this defaults to Phase 1 for both new and converted legacy builds. It's the third in the list and not obvious that it can be clicked, under Process and Get Sources. From there, it's under Execution Plan > Parallelism. The Multipliers field is still the same, but there's now an additional required field, Maximum Number of Agents. Using 1 will force each configuration to finish building before the next one begins, but you can increase it and it might build in parallel.

The final piece is on the Build tab, selecting the Copy and Publish Build Artifacts step. If you were to build now, it would build all four configurations, but drop all four zip files in the same directory, which isn't going to work since they'll all have the same name. My solution is to put each in their own folder, naming the folder for the configuration. This is very easy to do, just add "\$(BuildConfiguration)" (without quotes) after the artifact name in the Artifact Name textbox. Now it's safe to save and queue a build!

Interestingly, my build times decreased to around 14-15 minutes for each configuration. I'm pretty sure the deployment step wasn't taking 5 minutes on the old setup, but regardless, I like anything which makes the build faster!

If you switch over to the Release tab from the top row now, I've followed the tutorial down to the step where you create the release definition. I've created an Azure Website Deployment, disabled the test step, and renamed the environment to match one of my build configurations. I have four configurations, so I'll need four environments. I'll come back and add those in after I get the first one right. Continuing on the tutorial, I also linked to the build definition I created earlier. Once that's done, you can see the artifact name from your build in the Artifacts tab. Back on the Environments tab, we need to line up the configuration name for the release. Click on the three dots to the right of the environment name and select Configure Variables. Next to Release Configuration, I'll set the value to match the first entry in the build configuration list in the first image above, REL-IE.

Hit OK to save and return to the environments. There is a slight adjustment needed to the Web Deploy Package value in order to grab the correct deployment package for the current configuration. The default value of "$(System.DefaultWorkingDirectory)\**\*.zip" will grab all of the zip files in the build artifacts location. I have four configurations, so there are four zip files, each within a folder named for their build configuration. Using a syntax similar to the build step, modify this to look for this configuration folder using the ReleaseConfiguration variable we just set. This will make the value "$(System.DefaultWorkingDirectory)\**\$(ReleaseConfiguration)\**\*.zip". I have a staging slot set up for this web site/app service, so I've also set variables for the release to go to that slot as well.

Check the tutorial again for additional steps for continuous deployment and such. Otherwise, save and run a release - it should be good to go! The first time I tried mine, it failed for no logical reason, much like the old release system. Retried it and it worked, proving that I now have an improved way to release. Now we need to copy the existing environment over for the remaining three build configurations. The easiest way to do this is by clicking the three dots to the right of the environment name, and select Clone Environment. It will copy everything from the existing environment and let you change the name right away. The two things which need to updated now will be the ReleaseConfiguration variable value and the Web App Name for each. (If your sites are in different data centers, you may need to update the Web App Location value as well.) So I cloned the first configuration three times, updated those values, and saved, resulting in something like this:

Now select the release option from the menu, select the build which you queued earlier (and is hopefully done by now), and select the sites/configurations you want to deploy from left to right. My one complaint at this point is you cannot pick and choose which of the environments to deploy, you have to select them in order from left to right. Hopefully that option is added in the future. After selecting all of the configurations, mine worked on the first try, taking a little over 8 minutes.

To workaround the drawback around selecting a release out of order I mentioned above, I've also created individual releases for each of my build configurations in the event I need to deploy just one or two of them. All in all though, I'm really happy with how this turned out. While Release Management is still technically in preview, I'll be using this in production as it's such a significant improvement in my current release experience.

Extremely easy to do, but extremely easy to mess up. I’m assuming with this post you have already configured Azure Mobile Services with your certificates. If not, there are plenty of tutorials around which can help you through the process. (I personally like this one for APNS.)

The classic Mobile Services examples all involve the Todo List app, which expect you to be using the full Mobile Services backend. It’s certainly slick if you can, but what if you only need the push notification capabilities? This is the problem I was trying to solve. The data for my mobile application is already managed elsewhere, I only need Mobile Services to manage the push subscriptions for my end users. The Javascript API portion of Mobile Services will be called from my backend and by some other applications using C# to generate the push notifications. It’s maybe not a common scenario, but it’s certainly there to allow you to do it. No amount of Google/Bing attempts landed me on a nice tutorial which satisfied my questions, so I’ll do my best.

Go to the API tab in your mobile service in the portal, and either click on the Create option at the bottom or click the big message in the center of the screen. Enter the name you want for the API, I choose Godzilla. (There was a marathon on El Rey last weekend, so I have Godzilla on the brain still.) Set the app permissions appropriately for your API, I’ll to stick with “Anybody with the Application Key” for the example and click the Checkmark button.

Screenshot 2015-07-09 15.39.09

Once it’s done creating the API, click on it to view the code. You’ll have the starter API with a Post and a Get.

There’s no need for the Get, so delete it. The Post has a hint of what you need to use on the third line of comments, “var push =…”. Let’s uncomment that line so we can use it to generate the push. (I’m only going to write the code to send pushes to iOS (APNS) to keep the example nice and simple, the code for Android should be fairly trivial to add.) After the line with “var push = …”, paste in the following code over the remaining body of Post.

push.apns.send("atombomb", {
        alert: request.body.msg       
        success: function(result){
            //console.log("Godzilla push success");
       }, error: function(error){
           console.log("Godzilla push failed, error: " + error);
    response.send(statusCodes.OK, "{msg: 'Push executed, check log for results'}");

So what is this doing? It will push a notification to only the users subscribed to the “atombomb” tag. If you want to push to all users who have allowed push notifications for your app, change that parameter to null, without quotes around null. The next parameter is the JSON content which will be the contents of the push notification. (Here’s a great reference for more options you can put in it.) You see many other examples where they only use the payload property, which is certainly nice if you need to send some data with the push, but won’t actually pop a message on the user’s device. Alert is what you need to pop a message up, and the contents of the Alert parameter get displayed on the top of the user’s screen when it is received.

Quick side tangent. If you only provide the Payload property, as I did at first, it’s hugely confusing why there isn’t a notification popping up on the device. The portal will show the push succeeds, but nothing shows up on the device. The reference link above was the light bulb moment when I realized what I had done wrong. If there is no alert property as part of the content parameter, the user will not be notified in any way. You only want to use Payload by itself when you want to push an update in the background, without the user being prompted. You can certainly use both Alert and Payload at the same time, however.

On my alert parameter, you can see I’m actually sending in the content as part of the body of the API call. If you know your push message will always be the same, you can change this out for a string right there, but I think a parameter from the body makes for a better real world example. The final parameter contains the success and error functions, which are really useful for debugging. They will write to the mobile service log using console.log, which I’ll get to next. So here’s the final result:

Screenshot 2015-07-09 16.22.22

I also edited the response message, but you can leave it as the default if you like. Now click the save button at the bottom to save your changes. If you want to check the logs once you have called your new API, click the back arrow after saving and it’s the last option in the top menu. You may need to uncomment the body of the success function to get anything to appear there, if it all works right away.

Screenshot 2015-07-09 16.24.33

So now we need to call our API. This is when Mobile Services really flexes its muscles, it’s so incredibly simple. I’ve got a fairly reusable method for this which lets me pass in the API I want to call, and the message I want to send. So when invoking the method below, I use the parameters “Godzilla” for Api and “I knew that tuna-eating monster was useless!” for Message. If you’ve swapped out the message in the body for a string as I mentioned earlier, it gets even easier as you can then remove two lines which deal with the body variable.

public async Task SendPushNotification(string Api, string Message)
            JObject body = new JObject();
            body.Add("msg", Message);
	    MobileServiceClient client = new MobileServiceClient(appUrl, appKey);
            return await client.InvokeApiAsync(Api, body);

You can go much further with that method if you want, such as passing in your own custom object rather than using a JObject. If you’re looking to do something like that, I would recommend reading “Custom API in Mobile Services,” it goes nicely into a scenario like that, and includes a little bit on handling authenticated users.

Wow, that’s a long title. I didn’t know how to find it in Google when I was searching for terms similar to that earlier, so hopefully this post helps. So you’ve gone ahead and added push notifications to your Xamarin app using Azure Mobile Services. There are tons of tutorials out there to show you how to do it. The next logical step (if you love your users) is to add a setting someplace to allow users to turn off their push notifications. So then you go looking for good documents on how to update the tags that you subscribed to… and if they’re out there, they’re really hard to find. Here’s the quick and easy recipe: do the exact same thing as the initial registration, but with an empty (or updated) list of tags.

Setting this up with the boilerplate declaration:
var push = new MobileServiceClient(url,key).GetPush();

So to register one tag:
push.RegisterNativeAsync(deviceToken, new List<string>() { “tagname” });

And to unregister:
push.RegisterNativeAsync(deviceToken, new List<string>());

In the long list of tips to optimize your website performance are three things: use a CDN to serve content, make as few requests for Javascript and CSS as possible, and minify your Javascript and CSS files by removing whitespace and comments to make them as small as possible. ASP.Net provides a really excellent Bundling and Minification feature to handle the two latter points.This comes at a cost, however. Those static files must live within the project and can no longer be served via a CDN. (Not bundled, anyway.)

For a basic website, ASP.Net Bundling and Minification is fantastic. You set it up in the BundleConfig.cs file as described here, and you get a minified version of your Javascript in as few files as you configure. The Bundling tries to cope with a CDN through the UseCdn property there, but it doesn’t really work, in my opinion. It just spits out the URL on the page to the CDN, so you’re still left with a request for each library if the user doesn’t have the file cached yet. If you’re using something like jQuery UI, for example, it will probably be a request for jQuery, another for the jQuery UI Javascript file, and another for the jQuery UI theme you’ve specified. For these, all you’ve really done is replaced the old ScriptManager with another construct, and the various performance testing tools are still going to shout at you for making too many requests.

One of the guys on my team at work, Allan Bybee, took it upon himself to find a solution to this CDN bundling limitation. All of our Javascript and CSS files were previously being served from a CDN, so all of our static content lived out there rather than in the web project. Moving all of those files back into the project would have been a large task with many compromises to the development experience and web performance at the end. The critical one being that we would gain the bundling at the expense of serving files from the CDN. After a few weeks of digging around in the ASP.Net source code and diligent trial and error, he ended up with a really elegant solution which gives us the best of all worlds - source files that live in the CDN, which bundling watches for changes and then saves the resulting bundle back to the CDN. He did it by extending the built in ASP.Net bundling system, so it’s very similar to that - just improved upon. Here’s the best part: it’s now a Nuget package!


Azure Bundling on Nuget

Install from Nuget, and there is just a small amount of configuration in order to get things going. There are six settings that need configuring, and you have a three options for doing this. (Or read the full documentation.)

  1. Web.config - 6 required app settings
  2. Config.json - A file just for the settings
  3. BundleConfig - A different constructor

1. Web.config

<add key=“AzureAccountName” value=“your account name” />
<add key=“AzureAccessKey” value=“your access key” />
<add key=“CdnPath” value=“your cdn or Azure storage url” />
<add key=“SecureCdnPath” value=“your secure cdn or Azure storage url” />
<add key=“CachePolltime” value=“integer value in seconds how often to poll for file changes” />
<add key=“BundleCacheTTL” value=“integer value in seconds for cache time to live” />

2. Config.json

“AzureAccountName”: “your account name”,
“AzureAccessKey”: “your access key”,
“CdnPath”: “your cdn or Azure storage url”,
“SecureCdnPath”: “your secure cdn or Azure storage url”,
“CachePollTime”: “integer value in seconds how often to poll for file changes”,
“BundleCacheTTL”: “integer value in seconds for cache time to live”

If you use either of those first two configuration options, it will pick them up automatically and your BundleConfig code ends up very, very similar to what it was prior. Set up a variable that defines the Azure blob storage container name where the files live and the bundles will be stored in. (Make sure this container’s access level is not set to private, or none of this is going to work.) That variable is called AzureContainer in the code example below.

bundles.UseCdn = true;
BundleTable.EnableOptimizations = true;
BundleTable.VirtualPathProvider = new StorageVirtualPath(AzureContainer);
bundles.Add(new JSBundle(“~/your virtual path/jqueryVal”, “your folder”).Include(“~/your folder path/jquery.validate.js”, “~/your folder path/jquery.validate.unobtrusive.js”));
bundles.Add(new JSBundle(“~/your virtual path/modernizr”, “your folder”).Include(“~/your folder path/modernizr-2.6.2.js”));
bundles.Add(new CSSBundle(“~/your virtual path/site”, “your folder”).Include( “~/your folder path/bootstrap.css”, “~/your folder path/site.css”));

The key highlights from the code above are setting the VirtualPathProvider property on the BundleTable to an instance of StorageVirtualPath, and changing any ScriptBundle or StyleBundles which you want to be CDN bundles to instead be JSBundle or CSSBundle, respectively.

3. BundleConfig
Set up variables for each of the settings in the BundleConfig, and pass into the constructor for each of the custom bundling classes. (StorageVirtualPath, JSBundle, and CSSBundle.)

BundleTable.VirtualPathProvider = new StorageVirtualPath(AzureContainer, AzureAccountName, AzureAccessKey, CachePollTime);
var jquerycombined = new JSBundle(“~/bundles/jquerycombined”, AzureContainer, AzureAccountName, AzureAccessKey, CdnPath, SecureCdnPath, BundleCacheTTL).Include( “~/your folder path/jquery-2.1.3.js”, “~/your folder path/bootstrap.js”, “~/your folder path/respond.js”));

If you compare that code to the snippet above, you’ll notice the additional arguments being passed in on the StorageVirtualPath, JSBundle, and CSSBundle. These are the variables you’ll want to define with the appropriate values.

One last note on this is the order of precedence on the settings. Assuming you set it up in both the web.config and JSON file, the settings from the web.config will win over the JSON file. If you set it in the BundleConfig file, that will trump having either of the other two set.

This could not have been achieved without Microsoft making the move to open source .Net and ASP.Net. So if there’s something you don’t like about this, or find a bug, or want to contribute additional features to it, here’s the best part - it’s all on GitHub!


AzureBundling on GitHub

This project fills a big gap in ASP.Net bundling for those of us that are intensely focused on tuning the performance of websites. Allan has done a tremendous job figuring this out and putting it out there for the world (if you’re reading this Allan, thanks again!) and I hope that other developers find this as useful as I do. If you do, please make sure to report any issues you find, or better still, help contribute to this great project and make it even better!

Setting up CI to Azure Websites is extremely easy and convenient. Whether you choose to do it from Git or Visual Studio Online, having a staging deployment slot makes this absolutely dead simple to ensure that you’re putting high quality code into production so that a bad check in doesn’t affect live users. The problem is that search engine bots are super greedy and manage to start crawling your staging site, which you definitely don’t want - then real users may end up there. There are a few easy options you have to address this, and they aren’t very well documented at the moment.

The first trick is getting the name of the site you’re on, which you can do with the following:


If you’re on the staging site, this will return a value ending in So now you need a place to check for this.

I chose to do this with an HTTP Module, partly because I’m old school and partly because I want this check to happen before it gets into any ASP.Net work that ultimately won’t be necessary. The key bits are this:

string CurrentEnv = Environment.GetEnvironmentVariable(“WEBSITE_HOSTNAME”);
if (!string.IsNullOrEmpty(CurrentEnv) && CurrentEnv.ToLower().EndsWith(“”) && IsBot()) // Redirect to main site

There’s a second trick to get this working - it will stick if you release this and swap slots at this point. Go into the latest Azure portal ( at the time of writing) and add an app setting to both the production and staging slots, making sure you check the Slot Setting box. This forces the site to restart before it swaps to production. When you don’t have the sticky slot setting, the site doesn’t restart, and continues to get the staging value back from WEBSITE_HOSTNAME while in production. Name your sticky app setting whatever you like, it only matters that it is there. You can also set it via Powershell, if that’s more your speed.

To see this in action, use something that allows you to change your user agent to Googlebot and visit:

For full code, visit the Github repo for the site above. And if you do use the HTTP module method, be sure to register the module in the web.config in the system.webServer modules section.


1. See the Deployment Slot App Settings/… section

2. Detecting Honest Web Crawlers