64-bit IIS vs. 32-bit Assemblies

I found my first 64-bit bug at work. I was moving a windows service built for the ‘Any CPU’ to a 64-bit server. It started fine on the new server, and gave no indication of poor health in the logs, but one key function was malfunctioning. Im not exactly sure what the cause is, but I know that the hash of any binary file was resulting in the same value. The service does some direct memory manipulation which is a likely culprit.

Fixing the problem was easy: Set all the assemblies to compile for the 32-bit platform, check it in, build it, ship it.

Except that my web service now looks like this:

Server Error in ‘/MyApp’ Application.

Could not load file or assembly ‘MyCompany.MyApp.MyAssembly’ or one of its dependencies. An attempt was made to load a program with an incorrect format.

This application has two parts on the server: a windows service that processes emails, and a web service for interacting with them. The two parts share a database and a bunch of business logic, so they also share some assemblies. The windows service works great now that I’ve converted all the assemblies to 32-bit, but the web service wont start.

Although the error message is a bit misleading, it wasnt that hard to find the problem. When IIS is running in 64-bit mode (as it tends to do on 64-bit servers), all of its application pools will be 64-bit, and a 64-bit application pool cant load a 32 bit assembly. These are all the ways I can think of to fix it:

  • IIS 7 can run an application pool in 32-bit mode
  • IIS 6 can be configured to run in 32-bit mode, or you can run a second instance in 32-bit mode, though I dont imagine both instances could share the same ports
  • Write 32-bit and 64-bit versions for any platform-specific operations using conditional compilation, then build two versions of your assemblies
  • Rewrite the malfunctioning parts of your app so you dont have any platform-specific code
  • Compile most of your assemblies for ‘Any CPU’, but compile entry-point assemblies (such as my service executable) for 32-bit

A configuration-based solution isnt ideal based on the number and management practices of our environments. Finding and removing platform dependence would be the best technical solution, but it would be risky and time consuming. Switching some of my assemblies back to ‘Any CPU’ did the job with a minimal amount of impact.