Making the Silverlight XAP file expire from browser cache programmatically
Asked Answered
O

7

24

How to do I prevent a Silverlight XAP file being cached by the web browser?

The reason I want to do this is during development I don't want to manually clear the browser cache, I'm looking for a programmatic approach server side.

Ostosis answered 17/2, 2010 at 15:28 Comment(0)
D
26

Using IIS management add a custom header Cache-Control with the value no-cache. That'll cause the browser to check that any cached version of the XAP is the latest before using it.

Deterge answered 17/2, 2010 at 15:58 Comment(3)
This is a great response and much better than a lot of others (I have seen you give this answer here many times.) I am new to web development, but after reading the tutorial below...I can see this is exactly what is needed for XAP caching. It really is a great solution. Tutorial on CachingVevay
Would this not force the browser to never cache the XAP? Or does it ensure it only caches when the XAP is identical?Bisect
Is there a way to do that via Web.Config? My project is hosted in a server where i don't have access to IIS management.Defant
R
8

Add a query parameter to the URL for the XAP in the element on the HTML Page:

  • clientBin/MyApp.xap?rev=1
  • clientBin/MyApp.xap?rev=2

It will be ignored and break the cache. In IE8, there are some cache management tools: Open the Developer tools:

  • Try Cache...Always Refresh from Server
  • Try Cache...Clear Browser Cache for this domain...
Remorse answered 17/2, 2010 at 15:41 Comment(1)
Revision numbers on static resources can be quite effective when the URLs referencing them are generated dynamically so you can add these references. However it takes quite a bit of custom infrastructure to make this happen dynamically and without that the developer has to remember to upgrade the version number manually. It gets worse if the resource is used in multiple places. Since XAPs are not likely to be requested at high frequency from an individual client the occasional "unmodified" response is more desirable.Deterge
R
6

The solution presented here is somewhat similar to Michael's but is automatic and guarantees the client will always get a new version. This may be inefficient depending on your situation.

Since Lars says in his comments that he is not on Stack Overflow, I'm copying the response here.

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

  ....

</object>
Romans answered 25/5, 2011 at 19:31 Comment(4)
I gave this method a go and whilst I can debug and see the 'param' built correctly, the Response.Write writes in my example above the start of the <object> tag. Any ideas on how to resolve this one?Executrix
Huh...that's really odd. Maybe you could Response.Write the entire object tag including the param?Romans
It's odd indeed, I thought of writing the the whole lot out, which I did. Seems there is a framework we're using which doesn't handle response.writes in the location they are in the aspx/Response stream. Will raise a call with them and see if they can point me in the write direction. Thanks for the responseExecutrix
Doesn't work for PRISM apps where module XAPs are downloaded by the shell XAP.Breastfeed
F
5

Create a custom http handler for handling *.xap files and then set your caching options inside the handler.

Something like this...

using System;
using System.IO;
using System.Web;

public class FileCacheHandler : IHttpHandler
{
    public virtual void ProcessRequest(HttpContext context)
    {
        if (File.Exists(context.Request.PhysicalPath))
        {
            DateTime lastWriteTime = File.GetLastWriteTime(filePath);
            DateTime? modifiedSinceHeader = GetModifiedSinceHeader(context.Request);

            if (modifiedSinceHeader == null || lastWriteTime > modifiedSinceHeader)
            {
                context.Response.AddFileDependency(filePath);
                context.Response.Cache.SetLastModifiedFromFileDependencies();
                context.Response.Cache.SetCacheability(HttpCacheability.Public);
                context.Response.TransmitFile(filePath);
                context.Response.StatusCode = 200;
                context.Response.ContentType = "application/x-silverlight-app";
                context.Response.OutputStream.Flush();
            }
            else
            {
                context.Response.StatusCode = 304;
            }
        }
    }

    public DateTime? GetModifiedSinceHeader(HttpRequest request)
    {
        string modifiedSinceHeader = request.Headers["If-Modified-Since"];
        DateTime modifiedSince;
        if (string.IsNullOrEmpty(modifiedSinceHeader)
          || modifiedSinceHeader.Length == 0
          || !DateTime.TryParse(modifiedSinceHeader, out modifiedSince))
            return null;

        return modifiedSince;
    }
}
Fabulous answered 14/2, 2011 at 21:17 Comment(0)
B
5

I added a query parm to the path of the xap file, so that I can manage it through Versioning.

Default.aspx code:

<param
   name="source"
   value="ClientBin/MySilverLightApp.xap?xapid<%=XapID %>" />

Default.aspx.cs code:

protected string XapID
{
    get
    {
        Version v = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;

        if (System.Diagnostics.Debugger.IsAttached)
            Response.Write(string.Format("Build: {0}.{1}.{2}.{3}", v.Major.ToString(), v.Minor.ToString(), v.Build.ToString(), v.Revision.ToString()));
        return string.Format("{0}.{1}.{2}.{3}", v.Major.ToString(), v.Minor.ToString(), v.Build.ToString(), v.Revision.ToString()
    }
}
Berwickupontweed answered 29/1, 2013 at 16:55 Comment(0)
M
2

Well all the above examples depend on the browser NOT caching the HTML that contains the new trick xap name.... so you just move the problem on to something else. And they are also fiendishly complicated....

However for the debugging case, at least, it's easy to write the <object> and <param> tags in javascript so that the name changes every time the html page is used, whether it's cached by the browser or not!

<script type="text/javascript">
   document.write('<object blah blah >');
   document.write('<param name="Source" value="myapp.xap?'
               + new Date().getTime()+'">');
   document.write('</object>'); 
</script>

This sidesteps any hassle you may have controlling server settings and works just as well regardless of the server technology in use.

Note: you have to write the whole object group with the same method because putting a script tag inside the object tag means "only do this if the browser doesnt support the object.

Moonrise answered 23/6, 2011 at 20:59 Comment(0)
A
2

It’s not very uncommon to run into .XAP caching, which means that every time you deploy a new version of the Silverlight application, the browser does not download the updated .XAP file.

One solution could be to change the IIS properties. You can turn the “Enable Content Expiration HTTP header” option on for your .XAP file by following these step:

  1. Open IIS Manager
  2. Go to “Default Web Site” and find web site for your Silverlight project.
  3. Find the .XAP file under ClientBin.
  4. Go to the properties page of the .XAP file, on HTTP Headers Tab, Turn on “Enable Content Expiration”, click the “Expire Immediately” radio button.
  5. Save the changes.

This way the latest .XAP (only if there is a latest .XAP file) will get downloaded when you refresh your page without having to close the browser.

Hope this helps!

Arria answered 19/8, 2013 at 6:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.