Hosting Silverlight Applications in Azure Blob Storage

We have recently being doing a lot of work with Windows Azure and Silverlight and have found deployment one of the most involved aspects of Azure development. Building and deploying an Azure app currently takes up to 30 minutes and is not the simplest of processes so having to re-deploy every time you make a change to your Silverlight project can start to become a real pain.

So what's the answer? One answer is to separate your Silverlight XAP file from the Azure project by adding your Silverlight XAP file to the Azure Blob Storage. You can then update your Silverlight host page to download the XAP file directly from Blob storage.

This means you can just upload the latest Silverlight XAP file to Blob Storage and be up and running in a few minutes.

Below is a quick tutorial showing you how to do this:

Step 1 – Getting your Silverlight application ready for external hosting

If you just upload your current Silverlight XAP file to Blob storage and try and include it in your page you will find the page shows the loading screen, right up to 100%, and then just sits there. This is because your Silverlight application needs to be told to allow it to be hosted on a different domain that the Silverlight XAP file is hosted on. Your Azure application will be on myname.cloudapp.net but your XAP file will be hosted at myname.blob.core.windows.net.

To set the Silverlight project to allow external hosting open the App.manifest file (found in “Properties” folder of your Silverlight project ) and add the “ExternalCallersFromCrossDomain” attribute to the xml as follows:

   1: <Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment"
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   2:</span>         <span style="color: #ff0000">xmlns:x</span><span style="color: #0000ff">=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;</span> <span style="color: #ff0000">ExternalCallersFromCrossDomain</span><span style="color: #0000ff">=&quot;ScriptableOnly&quot;</span></pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   3:</span> <span style="color: #0000ff">&gt;</span></pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   4:</span>     <span style="color: #0000ff">&lt;</span><span style="color: #800000">Deployment.Parts</span><span style="color: #0000ff">&gt;</span></pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   5:</span>     <span style="color: #0000ff">&lt;/</span><span style="color: #800000">Deployment.Parts</span><span style="color: #0000ff">&gt;</span></pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   6:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">Deployment</span><span style="color: #0000ff">&gt;</span></pre>

 

Step 2 – Uploading the new XAP file

Now build your Silverlight project in release mode and find where the XAP file in creates (usually in the ClientBin folder of your web role project). You need to upload this to your Azure accounts blob storage and the easiest way to do this is by using the “SpaceBlock” tool on codeplex:

http://www.codeplex.com/spaceblock

Download the source code for the latest release (0.2.6 currently) by going to the “Source code” tab in codeplex and clicking the “Download” link next the the latest release.

1

Unfortunately you have to build the application yourself from sourcecode as there is not a version available for download currently with Azure storage support. Once built look for the “CodePlex.SpaceBlock.UI.exe” file and run this. You will need to add your Azure storage account details and then you should be ready to upload the XAP file.

In SpaceBlock open your Azure account in the bottom pane and the location of your new XAP file you want to upload in the top pane:

2

Right  click on the root folder of your Azure storage, in the bottom pane, and click “New Folder”. Give the folder a name like “xap” (be aware use lowercase name, either SpaceBlock or Azure don’t like uppercase). Now with your new folder selected in the bottom pane, right click on your XAP file in the top pane and click “Transfer”. This will open the file transfer dialog where you click “Start Transfer”

3

Your XAP file will then upload to your Blob storage, however by default it will not be publically accessible which you will need it to be.

To make it publically accessible right click on the new folder you created in your Blob storage and click “Edit Azure Container Access” and finally tick the “Allow public access” checkbox.

Your XAP file is now all ready to be used in your Azure web role.

Step 3 – Updating the Siverlight plugin host page

The final step is to update the page that hosts your Silverlight control in your Azure webrole project. For this tutorial I will assume your are using the ASP.net Silverlight plugin control. You need to make two changes to the asp.net control, firstly change the Source attribute to point to your XAP file in the Blob Storage. To get the url for this right click on the XAP file in the bottom pane of SpaceBlock and click “Generate URL”. Copy and paste the url into your asp.net page.

Secondly you need to add the attribute HtmlAccess="Enabled" to the asp.net silverlight control. After both these changes your code should look similar to this:

   1: <html xmlns="http://www.w3.org/1999/xhtml" style="height:100%;">
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   2:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">head</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">=&quot;Head1&quot;</span> <span style="color: #ff0000">runat</span><span style="color: #0000ff">=&quot;server&quot;</span><span style="color: #0000ff">&gt;</span></pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   3:</span>     <span style="color: #0000ff">&lt;</span><span style="color: #800000">title</span><span style="color: #0000ff">&gt;&lt;/</span><span style="color: #800000">title</span><span style="color: #0000ff">&gt;</span></pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   4:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">head</span><span style="color: #0000ff">&gt;</span></pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   5:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">body</span> <span style="color: #ff0000">style</span><span style="color: #0000ff">=&quot;height:100%;margin:0;&quot;</span><span style="color: #0000ff">&gt;</span></pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   6:</span>     <span style="color: #0000ff">&lt;</span><span style="color: #800000">form</span> <span style="color: #ff0000">id</span><span style="color: #0000ff">=&quot;form1&quot;</span> <span style="color: #ff0000">runat</span><span style="color: #0000ff">=&quot;server&quot;</span> <span style="color: #ff0000">style</span><span style="color: #0000ff">=&quot;height:100%;&quot;</span><span style="color: #0000ff">&gt;</span></pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   7:</span>         <span style="color: #0000ff">&lt;</span><span style="color: #800000">asp:ScriptManager</span> <span style="color: #ff0000">ID</span><span style="color: #0000ff">=&quot;ScriptManager1&quot;</span> <span style="color: #ff0000">runat</span><span style="color: #0000ff">=&quot;server&quot;</span><span style="color: #0000ff">&gt;&lt;/</span><span style="color: #800000">asp:ScriptManager</span><span style="color: #0000ff">&gt;</span></pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   8:</span>         <span style="color: #0000ff">&lt;</span><span style="color: #800000">div</span>  <span style="color: #ff0000">style</span><span style="color: #0000ff">=&quot;height:100%;&quot;</span><span style="color: #0000ff">&gt;</span></pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">   9:</span>             <span style="color: #0000ff">&lt;</span><span style="color: #800000">asp:Silverlight</span> <span style="color: #ff0000">ID</span><span style="color: #0000ff">=&quot;Xaml1&quot;</span> <span style="color: #ff0000">runat</span><span style="color: #0000ff">=&quot;server&quot;</span> <span style="color: #ff0000">Source</span><span style="color: #0000ff">=&quot;http://myname.blob.core.windows.net/xap/myappname.xap&quot;</span> <span style="color: #ff0000">MinimumVersion</span><span style="color: #0000ff">=&quot;2.0.31005.0&quot;</span> <span style="color: #ff0000">Width</span><span style="color: #0000ff">=&quot;100%&quot;</span> <span style="color: #ff0000">Height</span><span style="color: #0000ff">=&quot;100%&quot;</span> <span style="color: #ff0000">HtmlAccess</span><span style="color: #0000ff">=&quot;Enabled&quot;</span> <span style="color: #0000ff">/&gt;</span></pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  10:</span>         <span style="color: #0000ff">&lt;/</span><span style="color: #800000">div</span><span style="color: #0000ff">&gt;</span></pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  11:</span>     <span style="color: #0000ff">&lt;/</span><span style="color: #800000">form</span><span style="color: #0000ff">&gt;</span></pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  12:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">body</span><span style="color: #0000ff">&gt;</span></pre>

<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: white; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, &#39;Courier New&#39;, courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060">  13:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">html</span><span style="color: #0000ff">&gt;</span></pre>

Step 4 – Pulling it all together

Now if you build your Azure project in the normal way, and deploy it, you should hopefully find it is now reading the Silverlight XAP file from your Blob storage!

Next time you need to deploy your Silverlight application purely repeat Step 3 by uploading the new XAP file to the Blob storage.

Summary & Thanks

Hopefully you now see how easy it is to separate your Silverlight project from your main Azure project and you are ready to start saving deployment time. There are however a few downsides with this approach.

The speed of loading the XAP file from the blob storage is visibly slower than loading it from your azure web role, this is something we are happy to live with for the benefits it gives us.

Also by overwriting the old Silverlight XAP file with a new one you have no way to test a new deployment, as you would with the azure project. We worked around this by having the XAP file Blob storage URL as a setting in our ServiceConfiguration.cscfg file so that we could upload a to a new file and once checked change the ServiceConfiguration.cscfg setting to point to the new file. This required us to code the host asp.net to read from the ServiceConfiguration.cscfg file which we can change quickly without a new Azure deployment.

Thanks for this solution have to go to Yi-Lun Luo on this forum post which helped us solve our initial issues.