I was recently working on a Silverlight application where we used Silverlight Library Caching to help speed the load time of the site. By using library caching you specify different .ZIP files to build containing the assemblies your site needs. When a user accesses the site, all the .XAP and .ZIP files are downloaded simultaneously thereby speeding load time. Another benefit of library caching is that the browser will cache the resources so when the user re-visits your site, the browser will retrieve the resources from the cache instead of making a trip to the server.
The first step to do in order to use library caching is to select the “Reduce XAP size by using application library caching” option in your Silverlight project’s properties file. Then you need to specify which assemblies should be packaged together using an .EXTMAP file. The .EXTMAP file must be included with every assembly that will be packaged into the .ZIP file. In the .EXTMAP file there is a "downloadUri" for you to specify the name for the .ZIP. All the assemblies with the same downloadUri in their .EXTMAP will be packaged together into a .ZIP file. See this page for more details on how to setup library caching.
We had our Silverlight project set up so that our third party Silverlight assemblies were packaged in a separate .ZIP file. In addition, we packaged our own Silverlight assemblies into a .ZIP file for downloading. When we upgraded the site to the next version we were greeted with an error message and we were unable to log into the application. After I cleared the browser cache I was able to log in successfully.
Our Issue
So after upgrading, the user had to clear their browser cache to use the application. Although clearing the cache is an easy solution, it’s not an acceptable one. How was I going to fix this?
When the html page that hosts the Silverlight components loads, it calls a .XAP file to load the Silverlight application. Using the various browser developer tools I saw that the .XAP file that should have been retrieved from the server was retrieved from the browser cache with a 304 status. Even though I deployed a new application, the browser still retrieved the old .XAP file from the browser cache. I thought that the browser would detect that a newer version of the site is available and download the updated version -- well, it didn't.
Possible Solutions
I researched different ways for browsers to get the latest version. A lot of solutions recommended using a query string in order to force the browser to get the latest version. The query string would only need to change on each version released. That way, after the browser retrieved the latest version of the file after upgrade, it would cache the file for future visits. By adding the query string I was able to get the browser to download the new .XAP file when it was deployed. When I tested this solution it only got me past the login screen.
Main.XAP without query string in the html page.
Main.XAP with query string in the html page.
Using the query string allowed the latest .XAP files to be downloaded, however the .ZIP files (from the previous version) were still coming from the cache. The upgrade wasn't successful. I was stumped on how to solve this issue. Back to the drawing board to see if another solution existed. After some thinking I was able to figure out two more possible solutions to try. I couldn't modify a query string in order to get the updated .ZIP files because the references to those files get packaged with the AppManifest.xaml file in the XAP file, but I thought about renaming the .ZIP file altogether. If the file was named assemblies.zip it would be changed to assemblies_v2.zip in the next release. This was an easy change. In order to achieve this, I modified the “downloadUri” in the .EXTMAP file. I tested this solution and it worked. The downside to this approach is that the old .ZIP file will stick around on the server unless some process deletes it. The other solution I thought of was to include the contents of the .ZIP file in the Main.XAP file that gets loaded when the html pages loads. The .ZIP file is approximately 2MB and the Main .XAP file is approximately 85k. By combining the assemblies into Main.XAP I was potentially affecting the load time of the application.
The Solution
The final solution was to go with combining the assemblies in addition to using the query string. There wasn't much savings in terms of load time between downloading two files (2MB & 85k) and downloading one file (2MB + 85k). I didn't fear adding them together would impact load time. Having one file did resolve the issues that we had with the upgrade. In addition, we don't have to worry about older versions of the .ZIP files being left on the server.
What I Learned
What I learned from this experience is that if you have assemblies that are always changing in your Silverlight project, then package those with the Main.XAP file so that when a new version is released you don't have to worry about users not getting the latest copy of the assemblies. Use library caching for your third party assemblies since those are less likely to change once deployed.