0 Comments

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>());

0 Comments

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”));
bundles.Add(jquerycombined);

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!

0 Comments

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:

Environment.GetEnvironmentVariable(“WEBSITE_HOSTNAME”);

If you’re on the staging site, this will return a value ending in -staging.azurewebsites.net. 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(“-staging.azurewebsites.net”) && 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 (portal.azure.com 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: http://stagingbotredirector-staging.azurewebsites.net/

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.

Sources:

1. See the Deployment Slot App Settings/… section

2. Detecting Honest Web Crawlers

0 Comments
  •   Posted in: 
  • iOS

If I had to choose between using the Apple Developer Portal and going to the dentist, I’m going to the dentist. At least I know what pain to expect there. Here are some tips that I wish I had gotten before I had done any iOS development.

Developer vs Enterprise Account
The Enterprise account does not include the benefits of the Developer account, despite costing $200 more. And you need to set up two separate Apple IDs (email accounts) to have both. It’s buried in their program enrollment support page.

Push Notifications
You need two different certificates for this, dev and production, both of which need to be added the to the application in the portal. Then you’ll create a provisioning profile for development, ad-hoc, and app store. Ad-hoc will be used to test push notifications through the production server before the app hits the app store. You can only test push notification on a physical device.

If you use Azure Notification Hubs, never let a device with a development provisioning profile connect to the hub with the production push cert on it. The hub will be eternally ruined at that point, and you’ll have to recreate it. It will not give you any error messages about this, it will instead just stop working for no apparent reason.

Beta Testing
This should be done through TestFlight or another service. The IPA through iTunes method is a crapshoot at best.

iTunes Image Assets
These seem to only be used for the IPA through iTunes beta testing deployment, so don’t even do them.

Apple Developer Portal
It’s not just you, it really is an unusable disaster. Whoever built it should have been a dentist.

0 Comments

After this year’s build, I thought I would take a weekend to upgrade the Windows Phone version of Modern Delicious to 8.1. The new OS version added the ability to add the app to the Share Page option in mobile IE, a feature that it was badly lacking. Without this, the app was badly crippled in comparison to the Windows 8 version. As with anything that still is in a pre-release state, there were a few bumps in the road, so 1 weekend of work turned into 6.

Issues I Found

Share Contracts and JumpListItem Converters in the Emulator

There is a bug in the emulator that will cause it to hang if you add the Share Contract capability to the app and use a JumpListItemBackgroundConverter or JumpListItemForegroundConverter on any page in the app. Those converters are used in the new shared style, universal app phone projects to make Listviews in a Semantic Zoom control behave like the LongListSelector. These are completely unrelated to the share contract bits, so it was two solid weekends just to figure this out. However, these will work together just fine (as they should) on a physical device. It just makes testing kind of a pain, but luckily I do have a device to test on.

MSDN Forum Confirming the Issue

Associating App with the Windows Store Version

Developer portals are the bane of my existence lately. When submitting the new 8.1 version in the Phone developer portal, I went through all of the steps - added a the new appx package, added the description (again), added the submission notes (again), added the images and screenshots (again) and submitted. A button or checkbox to copy all of those things I had to do a second time would have been a big improvement since they were all basically identical to the 8.0 version, but I digress. After submitting, a head-scratching error occurs.

MD_Upload_Error

I had no idea what this was supposed to mean. Package name and language are empty, and the error reads, “The update is missing a package identity association: ”“. At the bottom of the page, there is a big button that says, "Go back and edit,” which of course I clicked. This was wrong, you actually need to click the tiny Edit link to the right of the error, which you can see in the image above.

While I was creating the appx package in Visual Studio, the step where you select the app name lists all of your apps - including Windows. So when I selected Modern Delicious there, it was actually linking the new phone 8.1 version of the app with the Windows 8.1 version of the app. This was good actually, it’s what I wanted in order to hopefully get the universal app icon in the store, it just wasn’t obvious what it was doing there. What the portal is saying is there a portal portion to this linking process that I needed to complete. When you click the edit link, it takes you to a page where you finish this process by selecting the Windows Store app again and clicking an “Associate” button to link the two.

The portal knew what needed to happen, but it didn’t communicate it well. I wish it would have just put that associate page in front of me rather than dump me onto the general submission error page without any useful instructions.

Links that Helped the Upgrade Process

All of these links were critical to me being able to upgrade Modern Delicious to Windows Phone 8.1. Without these, it would have taken me much longer than it already did.

App Bar Icon Symbol Names

Migrating from the LongListSelector to the ListView in Windows Phone 8.1 XAML Apps

Using a Behavior to Control the Progress Indicator in Windows Phone 8.1 XAML Apps