Tuesday, October 29, 2013

Enforcing JavaScript and CSS file refreshes on your ASP.NET website

A few years ago, I was part of a team that rolled out a website as part of a very large project.  The rollout on all aspects went reasonably well (except for one issue with a rather large page size, but we fixed that rather quickly).  One issue we had at launch however were some issues with existing users logging in for the first time.  Due to some funky logic we had in some JavaScript on our pages, some users were getting invalid error messages.  The bug was quickly identified and we rolled out the fix within an hour.  However, many of our users continued to have issues for hours after the fact.  The culprit was file caching.  In particular, our "login.js" file or whatever it was called was pushed to the web server, but web browsers were finding an existing file cached locally on the PC and were failing to download an updated version.
To force the new file to download, we went through all of our code, found references to all of our JS files (just to be safe) and appended a fake querystring value.  So our new code read as:

The querystring value can be arbitrary, just its presence gives the file a new name, and causes the web browser to detect a change and re-download the file, ignoring the cache.  However, now THIS file is now cached for some time, as all future references to login.js?x=123 will refer to the local copy.

So what if you want control over this programmatically?  Well, we have a few options.
The most basic method to handle this is to do what we did above, only add a value to your web config.  For example, add a configuration key called "CacheBuster".  In the ASP.NET world, it looks like this:
<add key="CacheBuster" value="X1235"/>
Now, you can refer to that value in our ASPX Markup, like so:
<script src="login.js?CacheBuster=<%=ConfigurationManager.AppSettings("CacheBuster")%>"></script>
This works for CSS files as well:
<link href="styles.css?CacheBuster=<%=ConfigurationManager.AppSettings("CacheBuster")%>" rel="stylesheet" />

See what we're doing there?  We're just referencing some value in our config file and appending it to our JS file reference.  Now, all references to the file will include our CacheBuster value.  So perhaps you are promoting a new website build and want to ensure that your users pull down the most current version of your JS or CSS files, you can just update the value in your config before deploying, and once the CacheBuster value has changed, it will ensure that all returning visitors get a new copy of your files.
Of course, we can do this from a timing perspective too.  Perhaps you want your users to pull a new file daily?  Just user the DateTime properties to create a unique value for that time period:
<script src="login.js?x=<%=DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString + DateTime.Now.Year.ToString()%>"></script>

This means that accessing the webpage today would provide "login.js?x=10292013", while accessing it tomorrow would result in login.js?x=10302013".  From this perspective, you have incredible flexibility.  You can use "Ticks" if you really wanted to to ensure that your users always pull the most current file (while also increasing all web traffic, of course).  Or, you can combine both methods listed above, giving a CacheBuster value along with a DateTime MMDDYYYY value, ensuring that you have flexibility on updating all cached copies of your JS and CSS files daily and\or whenever you promote a new build.
Hope this helps!

Thursday, October 24, 2013

Have other people test your code (and when it’s appropriate to use Hot Pink Comic Sans font)

I committed a mortal sin of mine recently, I chose not to let someone test some of my code.  I know better, but I was lazy, arrogant, aggravated, scared… you pick, it doesn’t matter, could be all of the above, either way, I should.. no.. do know better.

I’m working on a project that has been the most fun I’ve had in a long time.  I’ve gone shoulder deep in some jQuery\jQueryUI functionality on my front end UI, all managed by ASP.NET and hosted on Azure.  I’m performing AJAX JSON requests, updating HTML UI asynchronously based on user input, displaying modal windows, all stuff that nerdy people like me (and presumably you, since you are reading this) find cool.  I worked on a particular page for a few weeks.. not hours or days, but weeks.  I really put my heart and soul into getting a particular page.. what I thought was the crux of the site I’m developing, to function properly using the aforementioned technologies.  In the end, I was very happy, but thought of one or two features that would be helpful to have.  Namely, a “running total” of selected items (for all intents and purposes, think of this like a shopping cart “pick-a-product” page).  Since I recently finished the page, I knew what it took to get at the selected items, their prices, along with the additional options depending  on other items selected.  In the end, I was the only person looking at the site at this time and I told myself “eh, maybe phase 2”.

I know better…

I forwarded the site to my manager recently, and he was pleased with my progress, but he thought one or two elements were missing.  You guessed it, he thought we should display a running total and such.

Developer’s get involved in their coding process.  They rarely do the same thing twice, instead trying to use a slightly more efficient or updated methodology compared to a previous time.  When they encounter an issue, it becomes emotional.. it’s personal because it’s no longer programming but problem solving.  Some issues are solved in seconds.. others.. hours.  Combine that iteratively over each function on a website, app, whatever.. and you have many emotional hours invested in creating a Frankenstein… bringing something to life that once was never thought possible. 

In the end, when you finish writing code, it’s not a painting that dries and goes on display, it’s an evolving work that will change over and over and over.  The more important the software, the more change requests you’ll most likely receive.  Just because you work so hard at getting something “just right” doesn’t necessarily mean the software is just that.  Sometimes it’s best to ask your boss, co-worker, significant other or even your mother (no offense Mom!) their opinion on something.  At the end of the day, the only opinion that truly matters is your target audience.  If your demographic prefers Hot Pink Bold Comic Sans font.. well designer be damned.. put it on your site!

So if you’re reading this, and you develop software, get a second opinion on your software.  You may not always hear what you want to hear, but at least your software will meet the preferences of your end-users and not of the guys\gals that pieced it together, even if it did take them months to do so.

Wednesday, October 2, 2013

JavaScript Currency Formatter

I hate details.. that’s where the devil is.  I know it.. that’s what the saying says.  Nevertheless, the details are where many of my problems lie, yet I must continue to deal with them..  Today, my problem involved a number formatter, specifically a currency format.  A web app I’ve been working on is coming along rather smoothly, and using jQuery, jQueryUI and Twitter Bootstrap has given me some pretty cool UI features that I’ve been pleased with.  So, when it came to performing some custom validation and what-not, I started doing pretty cool things, like auto-formatting phone numbers and other numeric values while they were being typed. I then hit a wall, as I needed to apply numeric formatting to a currency value. This is apparently a sore spot for many others, so I thought I would share my Frankenstein creation of a currency formatter.

What did I build, well.. this: http://jsbin.com/IhUNAJo/2/embed?html,output

Glorious, right!?! Ehh, maybe not, but it's servicable, and I wanted to share it with the world. Here's the code:

How does this work? It's pretty simple. First, I'm using commafy, which is a prototype built by Steven Levithan. I'm using jQuery to capture the keyup\change events to alter my value (although this isn't necessary). Otherwise, I'm simply grabbing the current textbox value, stripping out anything that's not a number or a decimal value, adding comma's to the prefix (value before the decimal), and limiting the number to 2 values after the decimal.