Re-targeting existing .NET apps to a specific runtime version

File under “wow, I had no idea you could even do that”… also, file under “you really shouldn’t have to do that,” but that’s another story.

CPA clients are always an interesting challenge. By the standards of the IT world, their applications are really pretty simple and they don’t have a lot of data to deal with… but unfortunately, the tax codes they have to model were designed for human clerks physically stamping and filing papers in actual filing cabinets, not for modern data storage. Worse, those same tax codes vary from year to year, in arbitrary ways that seem “simple” from a human perspective but are difficult to fit into a logical framework. The end result is, your poor accountant has to deal with software that’s actually re-written once a year, every year, rather than a sane, logical framework that just gets a few variables tweaked from time to time.

Needless to say, quality control on this kind of software is frequently not all that it could be. In one particular case, a client was using an application called TaxWorks. The client has a nice, modern firm with a Windows Terminal Server for all of his accountants to do their work in. Doing it this way lets him (and me!) maintain the bewildering array of niche applications a CPA needs on a single machine, rather than having to keep them installed and updated across an entire network of workstations. For the most part, this is a great thing… but unfortunately, the folks who write TaxWorks apparently never did too much testing on any Windows Server platforms; the application works fine on Windows XP, and at first it worked fine on Server 2003 R2… until one day, my client called me and said TaxWorks just quit working. Which it did; the app would start but then would hang in several places. Many many hours of troubleshooting and many many calls to technical support later, we finally got to the root of the problem: on XP, TaxWorks works fine. But on Server 2003, TaxWorks stops working if any version of the .NET framework later than 2.0 gets installed.

For a while, we got by just avoiding installing .NET 3.0 and 3.5 from Windows Updates; but eventually, of course, one of the other applications on the server actually required .NET 3.5. The good news is, it turns out that even if you’re not the developer of a particular .NET app, you can target it to a specific version of the .NET runtime after-the-fact. It’s not particularly well documented – unless you’re a .NET developer yourself, in which case you should have done this BEFORE your app ever got in front of a customer – but the capability is there. .NET applications have an XML “application configuration file”, which is usually named “(yourapp).exe.config”, in the same directory as (yourapp).exe. Inside that configuration file, there should already be a supportedRuntime directive, which targets a specific version of the .NET framework… but if there isn’t one, you can insert it like this:

 <!-- JRS : attempting to force use of .NET v2 SP2 -->
 <startup>
    <supportedRuntime version="v2.0.50727" />
 </startup>

Of course, one of the challenges is figuring out what the heck runtime version corresponds to a human-readable “version” of .NET – it is extremely specific, and if you don’t get the string right, your app will then refuse to run.  After some trial and error navigating MSDN, I finally found this kb article showing the correct version strings for the various versions of the framework that are out there.  Long story short, if you drop to a cmd prompt and dir %systemroot%\Microsoft.NET\Framework, you’ll get a list of the versions of the .NET framework installed on the machine in question, in the formats you need to fill in the supportedRuntime directive in an application configuration file like the example above. With all that figured out, the code snippet above did the trick – the offending application no longer tries to reference the latest version of .NET installed; now it sticks to 2.0 (and works!) even with 3.5 also installed on the server.