Search code examples
silverlightsilverlight-5.0cdnazure-blob-storage

Can I host my Silverlight XAP file from a Azure Blob or CDN?


Having clients over the globe, we encountered some serious loading delays for initially retrieving the XAP from various locations. The hope was that we could host the compiled XAP in the cloud, offering a closer download depending on the end-user's location.

We are using RIA services, but the service endpoints need to remain on our local server, because of data connections, connections to internal services, etc.

How do we distribute the XAP using cloud-based services, while having it continue to function the same as it does currently?

EDIT: Since I worked through this and found the answer myself, I've moved the steps that I had accomplished before out of my question and into the answer to better facilitate a good Q&A format and for anyone else approaching the problem from step zero.


Solution

  • After hammering away at this, I found the solution to get it almost completely working.

    1. Update RIA service endpoints with absolute URIs to refer back to the hosting page rather than relative to the XAP location itself.
    2. Ensure all image (etc.) content is loaded from either resources in the XAP or else ensure they are uploaded as well to the Azure Storage Blob. Any relative paths will try to resolve to the XAP location.
    3. Generate the XAP file and upload to the Azure Storage Blob. You will need to ensure that the XAP has Content-Type of application/x-silverlight-app. I accomplished this using Azure Storage Explorer. You can set Content-Type by opening the properties of the item via double-click, but, and even better, you can click the Settings gear to 'Edit Content Types' and add a rule that .xap is application/x-silverlight-app so that it will be automatically set any time you upload.
    4. Ensure you have a proper cross domain policy in place.
    5. Update your hosting page to supply the new source. Additionally, you will need to add the enablehtmlaccess param if not already set, since this value is false by default for cross domain.

    For item #1, I accomplished using code such as the following:

    var u = HtmlPage.Document.DocumentUri;
    Site = u.AbsoluteUri.Substring(0, u.AbsoluteUri.LastIndexOf('/'));
    MyServiceUri = new Uri(Site + "/ClientBin/My-Namespace-MyService.svc", UriKind.Absolute);
    

    For item #4, my code looked like:

    <param name="source" value="<%= Request.Url.Scheme %>://mytest.blob.core.windows.net/my-container/MySilverlightApp.xap"/>
    <param name="enablehtmlaccess" value="true" />
    

    One last thing to note: If using a custom splash screen, then figure out how to get this to work. I don't know how. What I have found out is that if you set splashscreensource as the location of a .xaml file, then it simply does not load. It will just show the basic silverlight load percent screen, which does at least seem to report load % correctly. In order to get the custom splash screen to load, it seems to only work when included inline. You can do this via:

    <script id="xamlSplash" type="text/xaml">
        <%= System.IO.File.ReadAllText(Context.Server.MapPath("~/Loading.xaml")) %>
    </script>
    <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
        <param name="splashscreensource" value="#xamlSplash" />
    

    However, while this will show the custom splash screen, it will not work if you have any progress report on the splash screen. The javascript function referenced by onsourcedownloadprogresschanged will never fire. I could not find why this was the case, nor a way around it. You'll just have to have a spinning animation or the like in place of an actual % progress indicator.