A problem you can often run into, is that the client keeps the old version cached, which can break things in really weird ways.
This is a simple way to fix this - all you need to do is replace your script and link tags with this usercontrol.
That way, it ensures the url to the files gets a unique querystring added, which makes sure the client refreshes the file if it gets changed.
To do this, create a new class in a C# project, and call it HashedResourceFile, and paste the following code into it:
public class HashedResourceFile : WebControl { public Uri ResourceUrl { get; set; } private string FinalUrl { get { string url = ResourceUrl.ToString(); // Handle external URL's with not-defined protocol. if (url.StartsWith("//")) { return url; } // If the URL does not start with leading slash, it is external, and we don't do anything with it. if (!url.StartsWith("/")) { return url; } FileInfo fileInfo = new FileInfo(HttpContext.Current.Server.MapPath(url)); if (!fileInfo.Exists) { throw new FileNotFoundException("File in resource not found: " + ResourceUrl); } string hash; using (MD5 md5 = MD5.Create()) { using (FileStream stream = fileInfo.OpenRead()) { hash = BitConverter.ToString(md5.ComputeHash(stream)).Replace("-", string.Empty); } } return ResourceUrl + "?filehash=" + hash.Substring(0, 8); } } private ResourceLinkType LinkType { get { if (ResourceUrl.ToString().EndsWith(".css", StringComparison.InvariantCultureIgnoreCase)) { return ResourceLinkType.Css; } if (ResourceUrl.ToString().EndsWith(".js", StringComparison.InvariantCultureIgnoreCase)) { return ResourceLinkType.Javascript; } return ResourceLinkType.Invalid; } } protected override void Render(HtmlTextWriter writer) { if (writer == null) { throw new ArgumentNullException("writer", "writer must not be null"); } if (ResourceUrl == null || string.IsNullOrEmpty(ResourceUrl.ToString())) { return; } switch (LinkType) { case ResourceLinkType.Css: writer.Write("<link rel=\"stylesheet\" type=\"text/css\" href=\"{0}\" ", FinalUrl); foreach (string key in Attributes.Keys.Cast<string>().Where(key => key != "rel" && key != "type" && key != "href")) { writer.Write("{0}=\"{1}\" ", key, Attributes[key]); } writer.Write("/>"); break; case ResourceLinkType.Javascript: writer.Write("<script type=\"text/javascript\" src=\"{0}\" ", FinalUrl); foreach (string key in Attributes.Keys.Cast<string>().Where(key => key != "type" && key != "src")) { writer.Write("{0}=\"{1}\" ", key, Attributes[key]); } writer.Write("></script>"); break; default: return; } } private enum ResourceLinkType { Invalid, Css, Javascript } }
Then, when you create your project, add this to the top of the aspx/ascx file:
<%@ Register TagPrefix="test" Namespace="YourNamespace" Assembly="YourDLL" %>
Then, add this instead of your css/js file references:
<test:HashedResourceFile ResourceUrl="/static/css/style.css" runat="server" />
When the page is rendered, it will add a querystring to the file, containing a hash of the file, that changes when the file changes.
Really simple solution, to a really annoying problem :-)
Ingen kommentarer:
Send en kommentar