50
votes

When working with Silverlight, I've noticed that Firefox will cache the XAP file, so if I do an update, a user may be stuck using an outdated version. Is there a way to force the browser to either re-download the XAP file every time, or maybe only force it to after an update has been published? Or is there a setting in the Silverlight config that stops the browser from caching the XAP file altogether?

Thanks, jeff

17
I'm having this issue too. Thought my page changes didn't work, turns out I was looking at the cached version. Annoying.jcollum
I have a problem when using the cache tricks below on SL5 which were working on SL4, my question here: stackoverflow.com/questions/8974957/…jv42
I've added a bounty to my SL5 question, there doesn't seem to be much attention (stackoverflow.com/questions/8974957/…). If people have successfully used a similar strick with a SL5 runtime, I'm interested!jv42

17 Answers

32
votes

The query string works perfectly, but I wouldn't use DateTime.Now, because it forces the user to re-download the app every time. Instead, we use the following:

protected void Page_Load(object sender, EventArgs e)
{
    var versionNumber = Assembly.GetExecutingAssembly().GetName().Version.ToString();
    this.myApp.Source += "?" + versionNumber;
}

This way all you have to do is increment the version number in the AssemblyInfo.cs file.

12
votes

Simplest way:

<param name="source" value="ClientBin/App.xap?<%= DateTime.Now.Ticks %>" />
6
votes

This is what I do in php. You read the date/time of the xap file, and append it as a parameter to the download link. In that way the browser sees new file versions as new links, and therefore not in its cache.

<?php $fdate = date("dHis",filemtime("MyApp.xap")) ?>

<param name="source" value="MyApp.xap?=<?php echo $fdate ?>"/>

Simple and it works. Also, browsers continue to cache correctly when there are no updates to download.

5
votes

You might find the Caching Tutorial for Web Authors and Webmasters helpful. This document discusses the different caches through which the client and server interact (browser, proxy, gateway) and how caching can be controlled.

5
votes

For me, the best answer is from Chris Cairns. I've just adapted it a little, calling ToString and GetHashCode, generating an ID to the timestamp:

<param name="source" value="ClientBin/App.xap?<%= System.IO.File.GetLastWriteTime(Server.MapPath("ClientBin/App.xap")).ToString().GetHashCode()%>" />

Works just fine!

4
votes

You could send HTTP headers to prevent it from caching:

Cache-control: no-cache
Pragma: no-cache

How you do this depends on the web server you're using.

2
votes

Another solution would be to append the version of the XAP file rather than a timestamp. The timestamp would change every time (might as well turn off caching). To get it to only change when the XAP has been updated would be to take some info from the XAP file. Am still looking into what I could use, perhaps the last modified datestamp of the XAP file?

2
votes

Adding the timestamp for the XAP worked for me (I'm adding the SL control in javascript but this could just as easily be done inline):

var appTimestamp = '<%= System.IO.File.GetLastWriteTime(Server.MapPath("ClientBin/MyApp.xap")) %>';
var source = 'ClientBin/MyApp.xap?appTimestamp=' + appTimestamp;
2
votes

This tested and working:

Put this:

<%
    const string sourceValue = @"ClientBin/MyXapFile.xap";
    string param;

    if(System.Diagnostics.Debugger.IsAttached)
        param = "<param name=\"source\" value=\"" + sourceValue + "\" />";
    else
    {
        var xappath = HttpContext.Current.Server.MapPath(@"") + @"\" + sourceValue;
        var xapCreationDate = System.IO.File.GetLastWriteTime(xappath);

        param = "<param name=\"source\" value=\"" + sourceValue + "?ignore="
        + xapCreationDate + "\" />";
    }
    Response.Write(param);
%>

Instead of this:

<param name="source" value="ClientBin/MyXapFile.xap" />
1
votes

I'm getting this to work by a combination of the suggestions above:

  1. Set meta tag cache-control/pragma http-equiv attributes to 'No-Cache'
  2. Use an ASP.NET page to host the silverlight control (as opposed to an html page)
  3. Set the Source property of the ASP.NET Silverlight control in the code behind, appending a time stamp to the .xap url e.g.

    Silverlight1.Source = "ClientBin/MyApplication.xap?" + DateTime.Now.ToString("dd-MM-yy-HH:mm:ss");

1
votes

You can append the source url in the object tag with the last-write date of the XAP file. Check the code at my blog.

0
votes

We are also in the same situation wherein we want to control when the .XAP file gets downloaded to the browser.

An approach that you might want to take a look at is to use the Silverlight Isolated Storage as a "cache" to store your .XAP files.

Check out this blog: IsolatedStorage as a Silverlight object cache

0
votes

A super simple idea: just add a fake query string to the url.

<param name="source" value="app.xap?r12345"/>

Most servers should ignore it and server the file normally--depends on your server. If you get really clever, you could make the hosting page dynamic and automatically append a tick-count or date-time string to the query string. This ensures that you get caching when you want it, but force a download when there's a change.

Ideally, your server should do this for you. But if not...

0
votes

I had this issue so now when I start a new application I set the assembly version to 0.0.0.1 and just update it by one on every deployment, seems to have solved it for me. Then just set it back to 1.0.0.0 on release.

0
votes

So far, the only solution that I have found, once the problem occurs, is to clear the Firefox cache.

A better solution would be much better.

0
votes

I use this solution

<object id="Xaml1" data="data:application/x-silverlight-2," type="application/x-silverlight-2"
width="100%" height="100%">
<%––<param name="source" value="ClientBin/SilverlightApp.xap"/>––%>
<%
string orgSourceValue = @"ClientBin/SilverlightApp.xap";
string param;
if (System.Diagnostics.Debugger.IsAttached)
param = "<param name=\"source\" value=\"" + orgSourceValue + "\" />";
else
{
string xappath = HttpContext.Current.Server.MapPath(@"") + @"\" + orgSourceValue;
DateTime xapCreationDate = System.IO.File.GetLastWriteTime(xappath);
param = "<param name=\"source\" value=\"" + orgSourceValue + "?ignore="
+ xapCreationDate.ToString() + "\" />";
}
Response.Write(param);
%>
<param name="onError" value="onSilverlightError" 
-1
votes

The query string idea doesn't work for me in Silverlight 4. The server seems to cache the darned xap (though not the aspx file). The solution that does work in SL4 is to go to properties on your Silverlight project, go to Assembly info and put in a version.