Lars Holm Jensen's Code Blog

Just another WordPress codeblog on C#, Silverlight and all things .NET

Avoid incorrect Silverlight XAP file caching

with 46 comments

The code below appends the last-write filedate of the Silverlight Application XAP file to the path in the source parametre of the Silverlight object tag.
This will ensure that poorly constructed caching functionality of webbrowsers and proxy servers doesn’t incorrectly use old, wrong builds of the XAP file.
However it will still allow these caches to work. Furthermore a check is performed to avoid XAP file path alteration during debugging, this is to allow debugging tools such as Silverlight Spy to continue functioning.

<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" />

Written by larsholm

February 1st, 2010 at 8:06 pm

46 Responses to 'Avoid incorrect Silverlight XAP file caching'

Subscribe to comments with RSS or TrackBack to 'Avoid incorrect Silverlight XAP file caching'.

  1. Thanks, I had just run into this issue!

    Greg Hollywood

    2 Feb 10 at 6:14 am

  2. Your solution is professional against other “hack” styled or hardcoded solutions. Thank you, it was a lifesaver!

    Robert

    24 Feb 10 at 10:08 am

  3. Glad to hear it helped you guys

    larsholm

    24 Feb 10 at 8:56 pm

  4. I’ve come across this problem as well but I’m unsure where this code is meant to be

    I’ve pasted it in replacement of this line:

    but the resulted formatting doesn’t match that of here – e.g. it doesn’t recognise ‘string’ as a declaring type (its not blue)

    and it doesn’t recognise your string content inside the speech marks (not brown)

    and to be honest i dont understand what the @ symbols are

    i am using vb so pardon my ignorance (and i can see how dumb this sounds) but are u using javascript or c# here? i recognise “” from the linq-to-xml tutorials ive been using which is the only reason im asking about c#

    any help would be appreciated as this is exactly what i’ve been looking for – i just dont get it :S (which i can arrogantly say is unusual :P )

    Rahul

    1 Mar 10 at 9:23 pm

  5. Right-click your .aspx-file and choose View Markup and you will see something similar to the code in my post. Except the C# code will not work in your VB app. Instead replace the line in your .aspx-file that says
    <param name="source" value="ClientBin/VBSilverlight.xap"/>
    with this:

    <%
    Dim orgSourceValue As String = "ClientBin/VBSilverlight.xap"
    Dim param As String
    If (System.Diagnostics.Debugger.IsAttached) Then
    param = "<param name=""source"" value=""" + orgSourceValue + """ />"
    Else

    Dim xappath As String = HttpContext.Current.Server.MapPath("") + "\" + orgSourceValue
    Dim xapCreationDate As DateTime = System.IO.File.GetLastWriteTime(xappath)
    param = "<param name=""source"" value=""" + orgSourceValue + "?ignore=" + xapCreationDate.ToString() + """ />"
    End If

    Response.Write(param)

    %>

    Remember to change the name ‘VBSilverlight.xap’ to your application name.

    larsholm

    2 Mar 10 at 12:41 am

  6. oh ryt… i was using a html page not an aspx

    is there a way to do this in a html page or shall i just change back to an aspx page

    there was a specific reason i didnt use the aspx page (but its slipped my mind ryt now)

    cheers

    Rahul

    2 Mar 10 at 6:59 pm

  7. I suppose you could use PHP for this. But I don’t see why you wouldn’t use the inline VB as above in an .aspx-file?

    larsholm

    2 Mar 10 at 8:45 pm

  8. Thanks for a great solution Lars !

    Greetings from Norway, Stefaan

    Stefaan Rillaert

    16 Mar 10 at 11:22 am

  9. @Rahul

    Maybe your web hotel doesn’t support ASP.NET. Try this:

    <script language="php">
    $LastUpdated = filemtime("ClientBin/VBSilverlight.xap");
    echo ‘<param name="source" value="ClientBin/VBSilverlight.xap?ignore=’.$LastUpdated.’"/>’;
    </script>

    Still instead of the ‘<param name="source" ..’-tag and again.. Remember to exchange VBSilverlight with the name of your application..
    Of course this requires your filetype to be .php

    @Stefaan

    You’re welcome

    larsholm

    19 Mar 10 at 2:31 pm

  10. I can’t believe we have to go to these lengths, but yours looks like the best solution I’ve found.

    Worked for me!

    Toby

    14 Apr 10 at 3:19 am

  11. Worked perfectly for me. Thanks!

    Vincent Anzelone

    4 Jun 10 at 3:52 pm

  12. Hi there.

    I wanted to add that there seems to be a restriction to this. This solution only works completely correct if IIS is configured to send a (any!) content expiration header for your xap file. For example, you can set it to a date in the far future, or to a long time span.

    If the server does not deliver such a header, at least some browsers (e.g. Firefox 3.6.3) will pull the XAP file from the server _every time_, even when the source URL has not changed.

    The reason for that seems to be the URL parameter. If the source URL only points to the XAP file, it is cached on the client even without a content expiration header. As soon as you add any URL parameter (e.g. “?v1″ or a dynamically generated parameter like in your code), client-side caching is turned off by the browser unless an expiration date is explicitly set. So be careful with that and/or configure IIS correctly, or your users will be ending up with downloading the XAP file on every request.

    In IE8, it seems to work without the expiration header.

    Peter

    15 Jun 10 at 9:05 am

  13. Awesome! This is a lifesaver.

    Jon

    26 Jul 10 at 4:36 am

  14. Just had to add another note of thanks for the elegant solution to this problem.

    Brandon Sharp

    2 Aug 10 at 9:53 pm

  15. Thank you for this! Here is what I did using VB inside the SilverLight object tag:

    <param name="source" value="”/>

    Then in code behind (was already parsing some init params here from the request query string):

    Protected SourceString As String

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    If (Page.IsPostBack) Then
    Exit Sub
    End If

    SourceString = GetSourceString()
    End Sub

    Private Function GetSourceString() As String
    Dim OriginalSourceString As String = “ClientBin/MySlApplication.xap”

    If System.Diagnostics.Debugger.IsAttached Then
    Return OriginalSourceString
    Else
    Dim xapPath As String = HttpContext.Current.Server.MapPath(“”) & “\” & OriginalSourceString
    Dim xapCreationDate As DateTime = System.IO.File.GetLastWriteTime(xapPath)

    Return OriginalSourceString & “?ignore=” & xapCreationDate.ToString()
    End If
    End Function

    VGB.NET

    8 Sep 10 at 6:52 am

  16. Awesome dude!! Thanks!

    Travis

    17 Sep 10 at 1:09 am

  17. Very cool solution. Hadn’t thought of passing a querystring to the .xap file url, it’s ignored anyways! Great solution.

    Jim

    29 Sep 10 at 6:35 pm

  18. This will help me with some projects (thanks), but do you have any tips that will prevent XAPs and DLLs that loaded dynamically, from being cached?

    Thanks again for your tip above!!

    Anthony

    26 Dec 10 at 1:47 am

  19. Thanks for sharing knowledge

    http://soft-engineering.blogspot.com/

    bipin

    4 Jan 11 at 12:44 pm

  20. Hey, are you on StackOverflow? Because I think this is the answer to my question http://stackoverflow.com/questions/4674629/rapidly-iterating-silverlight-development

    If you want the reputation for it :)

    Thomas

    14 Jan 11 at 7:28 pm

  21. It’s ok, I’m not active on StackOverflow

    larsholm

    14 Jan 11 at 11:22 pm

  22. Lars,

    Do I need to configure IIS to cache xap objects, or is there a way to specify caching with code?

    Thanks

    Mike

    1 Feb 11 at 11:48 pm

  23. If you don’t experience any problems, there is no need to do anything specific towards caching. Most browsers have excellent caching mechanisms and ultimately it is the browsers that determines what is cached. In fact a browser can decide to use its cached copy without even connecting to the IIS. The IIS can however suggest an expiration time for content (search for ‘IIS Content Expiration’). It also has a feature called Output Caching but that is for dynamically generated content.
    Depending on what you want Isolated Storage might also be an option.

    larsholm

    2 Feb 11 at 12:13 am

  24. Hello Lars.

    Your solution works perfect, but I have a problem.
    When I using my application in OutOfBrowse mode and check for update using App.Current.CheckAndDownloadUpdateAsync() method, the method always works as if there is a new version of my silverlight application, even if the application is the same.

    Have You even hear about such behavior?

    Thanks.

    Martin

    2 Feb 11 at 1:13 pm

  25. Haven’t experienced that. This thread might help you.

    larsholm

    2 Feb 11 at 5:50 pm

  26. thanx, works great :)

    andrew

    9 Feb 11 at 11:11 am

  27. I am getting an error:

    “Invalid or malformed application: Check manifest”

    nagasadhu

    13 Apr 11 at 1:55 pm

  28. This fixes the caching problem, however, it looks like this blows up right-clicking. Using Silverlight 4.0 and I can handle right-click events just fine until adding the querystring. When that is added, I get the old “Silverlight” right-click menu intercepting all right-click events. Any thoughts on how to implement this solution without losing right-clickability?

    ryan

    28 Apr 11 at 10:27 pm

  29. Perfect! Thanks a lot.

    Alexander

    4 May 11 at 8:40 am

  30. Hi,

    My project has multiple modules in it. My startup project is just a dummy container and hence does not gets updated often. I want to load the modules within it to be updated whenever an update is available. The approach discussed above works good for the start-up xap but not for other modules. Could someone suggest a solution for modular loading of xap files when an update is available.

    Kasim

    17 May 11 at 11:13 am

  31. Hey Guys,

    Do you have solution for JavaScript ?
    I did try something like this :

    <!—->

    document.write(“”);

    But this is doesn’t work :(

    Norway

    15 Jun 11 at 8:44 pm

  32. hmm.. it seems to work fine for me:

    The Silverlight app loads fine with the code above..

    larsholm

    15 Jun 11 at 9:14 pm

  33. @kasim

    I’ve read this
    If you plan to have your users install the application OOB, and you expect to deploy updates to your application after it is deployed, you will need to stick to putting all the modules in a single XAP file. The Application.CheckAndDownloadUpdateAsync method will only go out and update the main XAP file that the application was launched from.

    pippo

    14 Jul 11 at 10:17 am

  34. It currently does not work if you use Firefox 4.0+ and your xap is greater than 5MB in size. It is a known bug:
    https://bugzilla.mozilla.org/show_bug.cgi?id=647391

    Guillermo

    27 Jul 11 at 9:54 am

  35. This seems to work fine until you use a Silverlight splash screen. I cannot get the tag in my splash screen to find the image. You can take the standard silverlight object tag and append ?x=y to the source xap like /ClientBin/MySLApp.xap?x=y and it will stop showing the image.

    Any ideas on how to make this work?

    scott

    23 Sep 11 at 11:49 pm

  36. Sorry my above posst had an actual image tag in it and the text didn’t come out how I wanted.

    I meant to say: I cannot get the image tag in my splash screen to find the image.

    scott

    24 Sep 11 at 12:07 am

  37. I have tried this but i am facing issue when my authentication service is getting loaded.
    This is the error i got after setting up the .xap file to have the date/time as you have given.

    Exception Details: System.IO.FileNotFoundException: Could not load file or assembly ‘App_Web_hjqoojxr, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null’ or one of its dependencies. The system cannot find the file specified.

    Can anyone please help me out?

    ishwarya

    6 Jan 12 at 1:24 pm

  38. Great solution! Thx!

    Matjaz Bravc

    9 Jan 12 at 3:29 pm

  39. How to you implement this for a PRISM framework implementation where the xap url is not hardcoded but dynamically constructed?

    Chan

    8 Feb 12 at 12:42 am

  40. Great solution,

    Many thanks

    Hasan the dude

    16 Mar 12 at 7:40 pm

  41. Chan,

    When you construct the xap URL, you need to append some query param which will get changed per release.

    E.g.

    ModuleInfo modInfo = new ModuleInfo()
    {
    ModuleName = “You_Module_Name”,
    ModuleType = “Type info”,
    Ref = “abc.xap” + “?version=” + GetVersionFromTypeInfo(),
    InitializationMode = InitializationMode.OnDemand
    };

    Mani

    6 Apr 12 at 4:09 pm

  42. ishwarya in your web.config change the batch compilation to false – this should fix it – and then change it back to true and it should still work

    here is an example from my config

    yipyipdog

    12 Apr 12 at 4:01 am

  43. this works great for zap file but what about zip files that are created by assembly caching?

    yipyipdog

    12 Apr 12 at 4:02 am

  44. I am still having issues in a LAMP environment. Is is possible to post a more specific example of a javascript/html only solution for this?

    Chris

    12 Apr 13 at 4:34 pm

  45. I really just want to understand what the significance of the “ignore” query string is. Essentially, this workaround does its job by passing in a query string with a value of the last written date from the Xap package on the server side.

    What does the browser do with this “ignore” query string? Is this some inbuilt functionality for browsers when dealing with cache? Is there some documentation somewhere on the significance of this?

    Christian

    13 Mar 14 at 2:02 am

  46. Hi,

    I ran into this issue too. Dometimes the app is loading. But after it is loaded, the screen stays white and the application is not rendered. Clear Cache solve this issue for a while. But after some days this issue returns.

    My silverlight app ist embedded in a content editor webpart on a SharePoint 2007 server. I can’t use ASP.NET.

    All I can do is the following:

    Is the a working solution without ASP.NET?

    Thanks in advance.

    Tomasz

    30 Apr 14 at 9:46 am

Leave a Reply

Spam Protection by WP-SpamFree