DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Subtitles: The Good, the Bad, and the Resource-Heavy
  • Loader Animations Using Anime.js
  • Next.js Theming: CSS Variables for Adaptive Data Visualization
  • Creating Scrolling Text With HTML, CSS, and JavaScript

Trending

  • Issue and Present Verifiable Credentials With Spring Boot and Android
  • Automatic Code Transformation With OpenRewrite
  • Java Virtual Threads and Scaling
  • Evolution of Cloud Services for MCP/A2A Protocols in AI Agents
  1. DZone
  2. Coding
  3. Languages
  4. Fingerprint CSS in MVC Web Sites

Fingerprint CSS in MVC Web Sites

By 
Merrick Chaffer user avatar
Merrick Chaffer
·
Jun. 20, 14 · Interview
Likes (0)
Comment
Save
Tweet
Share
11.4K Views

Join the DZone community and get the full member experience.

Join For Free

Optimizing for website performance includes setting long expiration dates on our static resources, such s images, stylesheets and JavaScript files. Doing that tells the browser to cache our files so it doesn’t have to request them every time the user loads a page. This is one of the most important things to do when optimizing websites.

In ASP.NET on IIS7+ it’s really easy. Just add this chunk of XML to the web.config’s <system.webServer> element:

<staticcontent>
  <clientcache cachecontrolmode="UseMaxAge" cachecontrolmaxage="365.00:00:00" />
</staticcontent>

The above code tells the browsers to automatically cache all static resources for 365 days. That’s good and you should do this right now.

The issue becomes clear the first time you make a change to any static file. How is the browser going to know that you made a change, so it can download the latest version of the file? The answer is that it can’t. It will keep serving the same cached version of the file for the next 365 days regardless of any changes you are making to the files.

Fingerprinting


The good news is that it is fairly trivial to make a change to our code, that changes the URL pointing to the static files and thereby tricking the browser into believing it’s a brand new resource that needs to be downloaded.

Here’s a little class that I use on several websites, that adds a fingerprint, or timestamp, to the URL of the static file.

using System; 
using System.IO; 
using System.Web; 
using System.Web.Caching; 
using System.Web.Hosting;

public class Fingerprint 
{ 
  public static string Tag(string rootRelativePath) 
  { 
    if (HttpRuntime.Cache[rootRelativePath] == null) 
    { 
      string absolute = HostingEnvironment.MapPath("~" + rootRelativePath);

      DateTime date = File.GetLastWriteTime(absolute); 
      int index = rootRelativePath.LastIndexOf('/');

      string result = rootRelativePath.Insert(index, "/v-" + date.Ticks); 
      HttpRuntime.Cache.Insert(rootRelativePath, result, new CacheDependency(absolute)); 
    }

      return HttpRuntime.Cache[rootRelativePath] as string; 
  } 
}

All you need to change in order to use this class, is to modify the references to the static files.

Modify references

Here’s what it looks like in Razor for the stylesheet reference:

<link rel="stylesheet" href="@Fingerprint.Tag("/content/site.css")" />

…and in WebForms:

<link rel="stylesheet" href="<%=Fingerprint.Tag(" />content/site.css") %>" />

The result of using the FingerPrint.Tag method will in this case be:

<link rel="stylesheet" href="/content/v-634933238684083941/site.css" />

Since the URL now has a reference to a non-existing folder (v-634933238684083941), we need to make the web server pretend it exist. We do that with URL rewriting.

URL rewrite

By adding this snippet of XML to the web.config’s <system.webServer> section, we instruct IIS 7+ to intercept all URLs with a folder name containing “v=[numbers]” and rewrite the URL to the original file path.

<rewrite>
  <rules>
    <rule name="fingerprint">
      <match url="([\S]+)(/v-[0-9]+/)([\S]+)" />
      <action type="Rewrite" url="{R:1}/{R:3}" />
    </rule>
  </rules>
</rewrite>

You can use this technique for all your JavaScript and image files as well.

The beauty is, that every time you change one of the referenced static files, the fingerprint will change as well. This creates a brand new URL every time so the browsers will download the updated files.

FYI, you need to run the AppPool in Integrated Pipeline mode for the <system.webServer> section to have any effect.

CSS

Published at DZone with permission of Merrick Chaffer, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Subtitles: The Good, the Bad, and the Resource-Heavy
  • Loader Animations Using Anime.js
  • Next.js Theming: CSS Variables for Adaptive Data Visualization
  • Creating Scrolling Text With HTML, CSS, and JavaScript

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: