If you’re like me, working in website design and development, then you love the ability to easily publish your enterprise web applications to Windows Azure websites. Visual Studio online makes this very easy, and the scalability and reliability of the service is top notch as well. We utilize both regularly at our digital agency in Boston, Cloud Construct.
One thing you may notice, though, is your storage allotment is capped at 10GB for the Basic tier and 50GB for the Standard tier. So, if your web application utilizes a large amount of assets like images or downloadable files, you can only store so much of it here.
First off, you shouldn't really be storing anything like this in your webroot anyway. You are restricted on deployment locations for the app because your web application depends on these files local to the website. Secondly, backups of the webroot will take a large amount of time and cost you more in storage fees. Not ideal.
These limitations exist because these items are not part of the core application functionality and should be placed in a location designed for this type of dynamic storage. That location is BLOB storage. Even though the file system utilized by Windows Azure websites, in fact, sits on BLOB storage, BLOB storage gives us a nice place to securely store files and serve files in a much more efficient way.
Let’s look at an example of how this would work for images and dynamic files like PDFs. Being located in Boston, one of the best sports cities in the US, the example I’ll use is a fantasy sports website. As you may know, these sites provide player bio information and head shots to users while drafting lineups.
The player head shots are a large amount of imagery that is not directly related to the design and style of the website. Not to mention they’re updated once a season. An image like this is a prime example of what should be moved to BLOB storage in a web application.
You can easily reference your head shots from a public container with the storage URL of http://xxxx.blob.core.windows.net/nfl/peyton.png. This not only reduces requests to your website server but also puts this asset in a location that can now take advantage of what Azure has to offer.
In the first part, we looked at how to utilize BLOB storage to make your web application and web development more scalable, while reducing its deployment footprint by moving dynamic assets like imagery and downloadable files into BLOB storage. Next, let's look at to improve web application performance with Azure CDN, so that your files are served fast and efficiently.
Now that the file http://xxxx.blob.core.windows.net/nfl/peyton.png is being served out of our BLOB storage account, we want to take advantage of the Azure CDN in order to serve the file quickly from servers all around the world. Once a file is requested through Azure CDN, the CDN checks the expiration date of the item, if it even exists, and requests it from BLOB storage if it needs it. After the file has been requested, that file remains in cache until it expires. This allows you to store web content all over the world and serve it rapidly.
The first step to enable CDN for your BLOB storage is to go to the Windows Azure portal and click on the CDN menu item from the left menu. Use the Create Button to easily add a new endpoint for your storage account.
After your endpoint is created, you will have a new URL to request your image from. It will be something like http://xxxx.vo.msecnd.net. This replaces the http://xxx.blob.core.windows.net portion of your previous URL. I enabled "https" and "query string" to my CDN as well, because my web application runs over SSL and I want to be able to cache bust the images if need be. On a side note: I added a custom domain to my CDN endpoint but was saddened to find out that I could not use that domain name over SSL. Microsoft still has not closed the loop on this feature yet. (http://feedback.azure.com/forums/169397-cdn/suggestions/1332683-access-to-cdn-over-ssl-https).
This means you will just need to use the URL specified in the portal with https prefixing it. (https://xxxx.vo.msecnd.net). I suggest making the use of the CDN dynamic in your web application based on if you are in production or not. You don't want to be wasting request costs over the CDN when you’re in web development mode, so dynamically switching from the BLOB URL and the CDN URL would be ideal for different environments. You can use a web.config transform to achieve this one:
web.config :
<add key="BLOBOrCDNLocation" value="http://xxx.blob.core.windows.net"/>
web.Release.config :
<add key="BLOBOrCDNLocation" value="https://xxxx.vo.msecnd.net"/>
You will notice in the release configuration we are using SSL and the CDN, where in the web development phase dev we are not using SSL or the CDN.
Azure CDN will cache your content for seven days by default. If you need to purge it, you can't directly do so at this time. You will need to access it with a querystring parameter like ?v=2.0 or delete it from BLOB storage and re-add it. Not ideal, but I hope they add this ability sooner rather than later so we can allow web development teams to automatically update items in cache without needing to have our app manage version strings.
There is one more way we can leverage the Azure CDN to make our web applications more efficient. And that’s by adding our JS and CSS bundles to the Azure CDN. By doing so, we can serve these static files much quicker from various locations around the world and from a separate endpoint than our website. To do this, you just add another CDN endpoint and map its origin domain to your Windows Azure website. You can see how to do this here:
Once this is mapped, you can access your published bundles via CDN endpoints. If you look at this code snippet from my BundleConfig.cs file, you can see how I am making sure to map my CDN endpoint to my bundles:
bundles.UseCdn = Convert.ToBoolean(ConfigurationManager.AppSettings["UseCDN"] ?? "false");
var version = ConfigurationManager.AppSettings["myAppVersion"] ?? "1.0.0";
var cdnUrl = "https://xxx.vo.msecnd.net/{0}?v=" + version; //Azure CDN does not support custom domain names with SSL
bundles.Add(new ScriptBundle("~/bundles/jquery", string.Format(cdnUrl, "bundles/jquery")).Include(
"~/Scripts/jquery-{version}.js", "~/Scripts/jquery-ui.js"));
There are a couple of useful settings here. First, setting the "UseCDN" property on bundles to be dynamic based on the web.config settings is important because we may want to turn this off in various environments or at different times. This, along with bundling in general, could be controlled by a single flag or just fallback to the default debug attribute being set to true/false. This is all up to you, but it is nice to be able to control this.
Secondly, we are setting up a version flag that we can bump up in the web.config file each time we publish to production (could be automated in a build process) so that we are guaranteed to serve fresh css/js to clients on every web application release. This is important so that clients are guaranteed new code each release. Lastly, we configure the jquery bundle to utilize our CDN URL to retrieve the bundle. Now after publishing the code, we see that the bundle in FireBug is in fact versioned and pulling from the CDN:
Awesome! We now have a great way to serve static content from our Windows Azure website to users in a fast and efficient way. The only other thing we might want to look into is utilizing the "CdnFallBackExpression" property on bundles in case the Azure CDN is ever not available. This will allow our code to pull the bundle locally until it comes back online. See this link: https://msdn.microsoft.com/en-us/library/system.web.optimization.bundle.cdnfallbackexpression(v=vs.110).aspx
I hope this article describes some useful ways to architect your web application in a way that makes it easier for you to scale out when needed. For our growing web development firm, utilizing tools and tricks like this have helped us to scale. Having these things configured early will ensure you are ready for any demands in traffic.
Helpful articles :
http://azure.microsoft.com/en-us/documentation/articles/cdn-websites-with-cdn/
http://azure.microsoft.com/en-us/documentation/articles/cdn-cloud-service-with-cdn/