50

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

Ether
  • 53,118
  • 13
  • 86
  • 159
Yttrium
  • 2,057
  • 7
  • 25
  • 28
  • I'm having this issue too. Thought my page changes didn't work, turns out I was looking at the cached version. Annoying. – jcollum Feb 26 '09 at 06:46
  • I have a problem when using the cache tricks below on SL5 which were working on SL4, my question here: http://stackoverflow.com/questions/8974957/silverlight-5-oob-update-broken-when-using-anti-cache-trick – jv42 Jan 23 '12 at 16:26
  • I've added a bounty to my SL5 question, there doesn't seem to be much attention (http://stackoverflow.com/questions/8974957/silverlight-5-oob-install-update-broken-when-using-anti-cache-trick). If people have successfully used a similar strick with a SL5 runtime, I'm interested! – jv42 Apr 22 '12 at 13:33

17 Answers17

32

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.

Romain
  • 2,318
  • 1
  • 23
  • 31
12

Simplest way:

<param name="source" value="ClientBin/App.xap?<%= DateTime.Now.Ticks %>" />
Andy Mehalick
  • 993
  • 8
  • 19
  • 7
    It would be much better to take the file date of the xap file instead. Then users would not have to download the app every time. – FlappySocks Dec 10 '09 at 17:36
  • How do you do that from codebehind, and insert that into the html page in place of the DateTime? Example please. – Stephen Price Jun 09 '10 at 02:12
  • You can give the param element an id and a runat="server" attribute to access it in code behind. Assuming id="SourceParam": SourceParam.Attributes["value"] += "?" + DateTime.Today.Ticks; – Andy Mehalick Jul 02 '10 at 21:14
6

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.

FlappySocks
  • 3,772
  • 3
  • 32
  • 33
5

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.

converter42
  • 7,400
  • 2
  • 29
  • 24
  • How does this answer the question? It doesn't address the specific issues of XAP files. – KevDog Sep 02 '09 at 13:42
  • 3
    KevDog: If, as Timothy Lee Russell says in his answer, clearing Firefox's cache fixes this, then that means Firefox (not the Silverlight plug-in) is requesting the file over HTTP just like any other Web resource and caching it using the same rules that apply to all content. Understanding the caching rules might help. – Jason Orendorff Dec 10 '09 at 18:00
5

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!

Community
  • 1
  • 1
JwJosefy
  • 730
  • 7
  • 12
4

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.

Jarett Millard
  • 5,802
  • 4
  • 41
  • 48
  • 3
    Timothy: You have to make sure those HTTP headers apply to the XAP file, not the HTML page. IIS lets you configure custom headers per folder: http://support.microsoft.com/kb/247404 – Jason Orendorff Dec 10 '09 at 17:54
  • if you are having your users download the same exact code every time they visit your silverlight application, especially when you have no changes... i am going to go out on a limb and say your doing it wrong. – felickz Apr 24 '12 at 11:39
2

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?

Stephen Price
  • 1,629
  • 1
  • 24
  • 42
2

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

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" />
Alexanderius
  • 822
  • 11
  • 27
1

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.

Lars Holm Jensen
  • 1,645
  • 1
  • 12
  • 14
1

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");

0

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

ptio
  • 206
  • 1
  • 7
  • Altought that does change the way the cache is being mantained it doesn't provide a way to know if an update has been made on the server, and that is due to silverlight code is run on the client and is not aware of a file on the server. You would have to use Isostorage to control the Date of the Downloaded Assemblies – Gabriel Guimarães May 25 '10 at 15:07
0

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...

Kevin Moore
  • 5,921
  • 2
  • 29
  • 43
  • It will work the first time, but not on subsequent requests, the query string value needs to be dynamic. – KevDog Sep 02 '09 at 13:42
0

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

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.

Timothy Lee Russell
  • 3,719
  • 1
  • 35
  • 43
  • This is important b/c it is the only way to -fix- the problem. Rather than focusing on preventing the problem. There is some data that you want to normally cache.. but as a developer you want to get the new copy. – ftrotter Jul 28 '10 at 17:54
0

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" 
Vladimir Dorokhov
  • 3,784
  • 2
  • 23
  • 26
-1

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.

Chris Bordeman
  • 255
  • 7
  • 19