Archived Posts from this Category
Archived Posts from this Category
In the presentation about Good API Design I talked about in yesterdays post one of the key points made was that once an API is defined you should never make changes to it that will break your client’s code. An example cited throwing exceptions based on values previously considered fine.
As luck would have it I encountered an actual example of precisely this problem today while installing the .NET 2.0 Runtime on a development server. This server runs a number of .NET 1.1 applications and a number of classic ASP applications consuming COM components written in .NET 1.1.
Things didn’t start well, with the framework installer stopping the IIS instance for the better part of 10 minutes while installing, however it did restart it again once it was done (unlike MSDTC and SQL Server when installing anything from the Windows Components section of Add Remove Programs on Windows 2003).
Matters got worse when someone mentioned that one of the components on the server was now misbehaving – specifically one that uses the ASP.NET Cache to provide caching capabilities.
Whenever a web application tried to create this object (via Server.CreateObject) it was getting an invalid pointer error. Other COM components developed in a similar way were working fine, so I assumed there was something wrong with the registration of the component. Un-registering and re-registering the component gave no joy – neither did calling it from a simple VBScript file.
To make matters worse, a simple .NET test application was working just fine using the exact same library.
After a bit of head scratching and pondering the SysInternals (Now a part of Microsoft) Process Explorer revealed that instead of using the .NET 1.1 version of System.Web both CScript and the IIS DLLHost were loading the .NET 2.0 version. The code for the component hadn’t changed, so maybe the .NET framework had.
Loading the source code for the component into Visual Studio 2005 and attempting to compile and run a the simple test application revealed the problem, a Null Reference Exception from within the framework.
As the COM Component was using the ASP.NET System.Web.Cache it was creating a HTTP Context instance internally. This code looked like this:
private System.Web.HttpContext context = new System.Web.HttpContext(null);
Poking round the disassembled code of System.Web in Reflector didn’t reveal what it was that was causing the exceptions, although I did only go a few functions deep, however it did reveal an alternative way of getting to the cache.
Changing our code to use a call to
System.Web.HttpRuntime.Cache to obtain the cache instance fixed our problem, and a quick rebuild of the component against .NET 2 and redeploy to the server and we were back up and running.
Lessons learned from all this:
When investigating performance problems on production servers it is always very useful to have as much information about the actual work that the server is performing at any given time. Out of the box IIS 6 does not give you much to work with – at best you can identify the virtual host that is causing the issues by putting it into its own application pool, and then using Task Manager you can see PID of the w3wp.exe instance which is occupying your servers CPU. Once you have that, the iisapp.vbs administrative script will reveal the name of the application pool which is misbehaving.
I have often wished to be able to see in real time what is actually going on within the worker process or IIS instance, and with the discovery of the Internet Information Services Diagnostic Tools trace tools I have found something that comes pretty close to what I would like.
The IIS trace tools contain a command line tool that will return the details of the executing requests as XML (even obtaining the information from a remote IIS server), however the jewel in the crown is the Request Viewer – a window app that with the click of a tool bar button reveals the requests currently executing on the server. (see screen shot below)
Unfortunately the tool does not show you the name of the host that the requests relate to, just the site ID and application pool pid, but these are easily converted into the application pool name (as mentioned above, use iisapp) or the site (look the is up in the IIS Manager.
Another problem with the request viewer is that when I first ran and clicked the refresh now button it all I got was an error and no details of the requests currently running. Thankfully I found the solution on the web, and it was as simple as making sure the temp environment variable was set to a path that didn’t use long filenames.
As the IIS viewer leaves a command window in the background when it runs, I thought that the best solution would be to have a simple batch file that set the environment up, ran IISApp.VBS and then started the Request Viewer:
"C:\Program Files\IIS Resources\TraceDiag\reqviewer.exe"
So now that empty command window contains the PID values for all my application pools so its not wasting space in my RDP window 🙂