On a recent POC we found a bit of a problem with the time it was talking to deploy our application to Azure’s staging environment then deploy it into production. Now I must point out that we had a token that allowed us to have quite a lot of machine instances and those machines were being built and deployed far faster than I could build them – well actually faster than I could find my Windows 2008 DVD! However this time lag didn’t fit very well with the development cycle of our Silverlight UI. The application was basically a big XAP that talked to WCF services hosted in an Azure web role. As we approached the end of the POC, we were making infrequent changes to our service layer, but the UI code was being update very frequently – mostly small cosmetic fixes.

When deploying an Azure web role, you need to package up the contents of your site - including all the static content, i.e. any Silverlight XAPs. This means that for every UI change that we wanted to preview/test against our Azure services we needed to deploy the whole application. To solve this problem we changed our app so that our XAPs were stored in the Azure blob store; allowing us to upload them whenever we wanted with almost zero turn round time – in fact our last build of the UI was less than 60 seconds before the demo!

To do this required the following changes:

  1. An ASP.Net page to upload an XAP into the blob store – not strictly necessary as you could use a tool like SpaceBlock to do this for you.
  2. An ASP.Net handler to serve the requests for XAPs
  3. Changing the embedded Silverlight tags to point at the handler rather than the static file (normally in ClientBin)

The upload page

Ok this won’t win any coding awards, nor should you put this into production, but it worked for our POC and is enough to get you started:

    protected void Button1_Click(object sender, EventArgs e)
    {
        StoreXap(FileUpload1.FileName, this.FileUpload1.FileBytes);
    }

    protected void StoreXap(String name, byte[] data)
    {
        BlobContainer container = SLDownloader.GetBlobContainerForSLXaps();

        BlobProperties blobProps = new BlobProperties(name);
        blobProps.ContentType = "application/x-silverlight-2";

        BlobContents blobConts = new BlobContents(data);
        container.CreateBlob(blobProps, blobConts, true);
    }

    private static BlobContainer GetBlobContainerForSLXaps()
    {
        StorageAccountInfo sai = StorageAccountInfo.GetDefaultBlobStorageAccountFromConfiguration();
        BlobStorage blobStorage = BlobStorage.Create(sai);

        BlobContainer container = blobStorage.GetBlobContainer("XAP");
        container.CreateContainer();
 
        return container;
    }

Where FileUpload1 is just an ASP.Net upload control:

    <form id="form1" runat="server">
    <div>
        <asp:FileUpload ID="FileUpload1" runat="server" />
    </div>
    <asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Button" />
    </form>

The ASP.Net Handler

The ASP.Net handler looks like:

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class SLDownloader : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        WriteImageToHttpResponse(context.Request.QueryString["xap"], context.Response);
    }

    public static void WriteImageToHttpResponse(String xapName, HttpResponse response)
    {
        byte[] xapData = null;
        String contentType;
        BlobContainer container = GetBlobContainerForSLXaps();

        MemoryStream ms = new MemoryStream();
        BlobContents blobConts = new BlobContents(ms);
        BlobProperties blobProps = null;
        try
        {
            blobProps = container.GetBlob(xapName, blobConts, false);
            xapData = ms.GetBuffer();
            response.ContentType = blobProps.ContentType;
            response.OutputStream.Write(xapData, 0, xapData.Length);
        }
        catch (StorageClientException sce) 
        {
            // Ok, the XAP we wasn't isn't there, return a 404?
            // ...
        }
    }

    public bool IsReusable
    {
        get { return false; }
    }
}

Changing the tag

And finally fix up the Silverlight control so that it gets the XAP from the handler rather than from the more conventional static file in ClientBin:

    protected void Page_Load(object sender, EventArgs e)
    {
        Xaml1.Source = "~/SLDownloader.ashx?xap=MySilverlightApp.xap";
    }

We could have just made the blob container public pointed the Silverlight straight at the XAP blob, but in this case there were a few reasons for using the handler:

  1. I knew that using the handler would work – I needed to get it working quickly
  2. Wouldn’t cause any issues with Silverlight’s web service policy 
  3. We were using LiveId for authentication and I didn’t want to bypass any checks we were doing and download the XAP to just anyone and
  4. I modified the handler to return the file from the ClientBin directory if the blob didn’t exist – i.e. the blob version overrode the one that was shipped – it was a demo app and I was worried that we might forget to upload the XAP to storage ;-)

Easy and quite a powerful technique to decouple your XAPs – well any static content - from your Azure deployment package.

Neil.