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:
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 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; } } }
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:
Easy and quite a powerful technique to decouple your XAPs – well any static content - from your Azure deployment package.
Neil.