HOWTO: Replace an ISAPI DLL on a Live Server

Recently, I noticed that I was returning into the bad habit of making just newsgroup replies instead of making detailed blog posts about the question and then posting that URL to the newsgroup. Here's an interesting one about replacing live ISAPI DLLs... but what does making IIS always cache a DLL have anything to do with replacing an ISAPI DLL? Read on...

Question

I'm testing a new and empty IIS 6 site, with my ISAPI application. I created a new App Pool for the scripts directory and I notice that sometimes my dll is cached (and sometimes it's not). I ALWAYS want to cache the dll and the related files, so I tried setting the MaxCachedFileSize registry entry to a higher value, but the problem persists.

How do I force work process to always cache the dll?

The number entered in MaxCachedFileSize is bytes? or kbytes?

Thanks.

Answer:

By default, IIS6 caches the ISAPI Extension DLL on first access of the DLL.  IIS6 has no way to cache "related files" used by the ISAPI DLL unless the files are directly served by IIS.

In other words, MaxCachedFileSize has nothing to do with caching ISAPI DLLs nor its related files, so do not fiddle around with it. Can you provide the documentation which told you to change these settings for your issue?

The configuration which controls whether IIS caches the ISAPI Extension DLL or not is the "Cache ISAPI applications" checkbox inside of the "App Mappings" tab of the "Configuration" button inside the "Home Directory" tab of the website/vdir right-click Properties page. It is set by default and should remain set by default.

Response:

> Can you provide the documentation which told you
> to change these settings for your issue?

The IIS 6, but obviously I got confussed.

The fact is that, sometimes, IIS does not cache the ISAPI library and retains access to DLL. I mean: If I try to delete or replace the .dll file access is denied (until I recycle the app pool). So... this is my idea:

1) IIS always cache DLL so
2) The dll is always in memory (access to file is not denied)
3) If I want to replace the DLL by a newer version I simple copy
4) To let the new version start working I recycle the app pool

Thanks!

My Response:

Ah, I see where you are getting confused with concepts and terminology. Let me try to explain what is going on and how to accomplish what you are describing.

What you are trying to accomplish is to replace an in-use ISAPI DLL (i.e. one that has been loaded and used on the server). Typical situations which require this are:

  1. You are developing and debugging the ISAPI DLL, so you want to load and trigger the ISAPI DLL for testing, then replace the ISAPI DLL with an update and repeat.
  2. You are running a website that uses the ISAPI DLL but you want to update the ISAPI DLL without necessarily bringing the entire application/website down.

Where you are getting confused is your incorrect assumption that "If IIS caches the ISAPI DLL in memory, then access is not retained on the DLL file on disk and I can delete/replace it"... because the exact opposite is what actually happens. Thus, your idea does not work because it assumes several behaviors that simply does not exist.

IIS6 does not load ISAPI DLLs for execution until you make an explicit request which requires it. In fact, IIS6 does not even consume system resources to handle that request until it happens and demand starts the worker process to optimize and conserve system resources for the most popular activities.

When that first request involving the ISAPI DLL happens, IIS loads and retains the ISAPI DLL into memory (if "Cache ISAPI applications" is checked - by default), and the physical DLL file on disk is also locked so that it cannot be deleted/updated. This is why the "Cache ISAPI applications" checkbox exists - when it is unchecked, IIS does not leave the DLL loaded in memory and instead loads/unloads on every explicit request, so the physical file on disk is not locked and you can replace it with a newer version at any time as long as there is no request using it.

In other words, when debugging your ISAPI DLL and making frequent changes, you can uncheck "Cache ISAPI applications" and freely update the ISAPI DLL and test. On production systems, you want to leave that option checked because you do not frequently change the ISAPI DLL, and the constant DLL load/unload will drain server performance as well as expose startup/shutdown race condition bugs in ISAPI DLLs.

This gets to the issue of how to gracefully update an ISAPI DLL while a server is using it, and here is how to do it:

  1. Rename the existing ISAPI DLL to something else. NTFS allows you to rename the DLL and existing process with that DLL image loaded is still ok. This means existing in-flight requests continue using the old DLL.
  2. Copy over the new ISAPI DLL. New requests now use the new DLL. There is a slight race condition here, between when you rename the old DLL and copy over the new DLL, where requests will not see a DLL at all.
  3. At some future time, when requests using the old DLL complete and and your application pool recycles (so the DLL is unloaded from memory), you can delete the old renamed DLL.

Users/Applications won't notice anything different (application pool recycling does not break connections), but you just transparently updated the ISAPI DLL on the server...

//David