The other day I shared how to use the DirectoryServices namespace to restart an app pool via C# code. The code I used had two key flaws:
- It used a Thread.Sleep(2000) to wait for the old app pool to be destroyed.
- The use of DirectoryServices required the enabling of the windows feature: IIS Metabase and IIS 6 configuration compatibility.
Also just to recap why you would even want to do this: My use of this code is for writing integration tests of web app functionality. It allows me to test scenarios where I want to ensure a certain outcome after the application restarts. It also helps to isolate test state from one test to another.
Anyhoo, a coworker of mine, @mmanela (Matt Manela) mentioned hosting a powershell script instead of the DirectoryServices implementation. As we discussed it further, we assumed that the PowerShell WebAdministrationiModule was probably using some other API and that it would be interesting to discover what that was and see if you could use that. Well after spending some quality time with reflector and the WebAdministrationModule DLLs, I was not able to tell what that API was. However, I did discover another API that appeared to be a better alternative to DirectoryServices.
The API can be found in %WinDir%\system32\Inetsrv\Microsoft.Web.Administration.dll. See this post for a good overview. Here is my new helper method:
public static void RecyclePool(){ using (var manager = new ServerManager()) { var pool = manager.ApplicationPools["RequestReduce"]; Process process = null; if(pool.WorkerProcesses.Count > 0) process = Process.GetProcessById(pool.WorkerProcesses[0].ProcessId); pool.Recycle(); if(process != null) { while (!process.HasExited) Thread.Sleep(0); process.Dispose(); } }}
So in addition to using a different API, I’m also no longer using the hacky Thread.Sleep(2000) to wait for the app pool to die. Instead, I use this API to get the Process ID of the about to be recycled app pool. I then wait for the pool to exit. I have tested this and it works perfectly. So now my tests move on as soon as the app pool is completely destroyed. I don’t have to wait any extra time in case this happens more quickly than two seconds and I don’t risk a failed test if two seconds is not long enough. In case you are wondering why it is so important to wait for the old app pool’s worker process to terminate before proceeding, it is because I may have cleanup code that deletes files and that code will likely fail if the old worker process had a lock on the file.