PRB: System.InvalidOperationException Error When You Use HttpWebRequest and HttpWebResponse Classes in Application with Thread Pool (815637)



The information in this article applies to:

  • Microsoft ASP.NET (included with the .NET Framework) 1.0
  • Microsoft ASP.NET (included with the .NET Framework 1.1)

SYMPTOMS

When you use the System.Net.HttpWebRequest and the System.Net.HttpWebResponse classes in an application that uses a thread pool, you may receive the following error message:
System.InvalidOperationException: There were not enough free threads in the ThreadPool object to complete the operation

CAUSE

The System.Net.HttpWebRequest and the System.Net.HttpWebResponse classes always use asynchronous methods to complete a request. When the asynchronous request is made, ASP.NET uses a new thread from the ThreadPool object. When ASP.NET does not find a thread, the System.Net.HttpWebRequest class returns the error message instead of queuing the request.

WORKAROUND

To work around this problem, use one of the following methods:
  • Use a Try-Catch block in the code to catch the exception and to handle it appropriately.
  • Implement a queuing mechanism to keep the exception from occurring.
  • If you are using ASP.NET in Microsoft Internet Information Services 5.0 or later, reconfigure the thread pool size in the Machine.config file. To do this, follow these steps:
    1. Open the Machine.config file from the %Systemroot%\Microsoft.NET\Framework\Version\CONFIG folder.
    2. In the <processModel> section of the Machine.config file, configure the value of the maxWorkerThreads and the maxIoThreads attributes to the maximum number of threads for the process for each CPU. For example, if this value is 25 on a single-processor server, ASP.NET uses the run-time application programming interfaces (APIs) to set the process limit to 25. On a two-processor server, the limit is set to 50.

      Note Monitor the CPU usage when you increase a thread pool to maintain the limits.
    3. Save the changes to the Machine.config file.

STATUS

This behavior is by design.

MORE INFORMATION

  1. Start Microsoft Visual Studio .NET.
  2. On the File menu, point to New, and then click Project.
  3. Click Visual Basic Projects or Visual C# Projects under Project Types, and then click Console Application under Templates.
  4. Replace the code in the Class1 code window with the following code, depending on your project type:

    Visual C# .NET Code
    using System;
    using System.IO;
    using System.Net;
    using System.Text;
    using System.Threading;
    using System.Net.Sockets;
    
    namespace threadTest
    {
      
    	class Class1
    	{
    		 public static void Main()
    		{			
    		// Set number of threads to be created for testing.
    			int testThreads = 55;
    			for(int i=0;i<testThreads;i++)
    			{
    				ThreadPool.QueueUserWorkItem(new WaitCallback(PoolFunc));
    			}
    			Console.ReadLine();
    		}
    
    		static void PoolFunc(object state)
    		{
    			int workerThreads,completionPortThreads;
    			ThreadPool.GetAvailableThreads(out workerThreads,
    				out completionPortThreads);
    			Console.WriteLine("WorkerThreads: {0}, CompletionPortThreads: {1}", 
    			workerThreads, completionPortThreads);
    			Thread.Sleep(10000);
    			
    			string url ="http://www.msn.com";         
    			
    			HttpWebRequest myHttpWebRequest ; 
    			HttpWebResponse myHttpWebResponse=null ;        
    			// Creates an HttpWebRequest for the specified URL.    
    			myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url); 
    			// Sends the HttpWebRequest, and waits for a response.
    			myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();            
    			myHttpWebResponse.Close();
    		}
    	}
    }
    
    Visual Basic .NET Code
    Imports System.IO
    Imports System.Net
    Imports System.Text
    Imports System.Threading
    Imports System.Net.Sockets
    
    Module Module1
    
       Sub Main()
          'Set number of threads to be created for testing.
          Dim testThreads As Integer = 55
          Dim i As Integer
    
          For i = 0 To testThreads
             ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf PoolFunc))
          Next
          Console.ReadLine()
    
       End Sub
       Public Sub PoolFunc(ByVal state As Object)
    
          Dim workerThreads, completionPortThreads As Integer
    
          ThreadPool.GetAvailableThreads(workerThreads, completionPortThreads)
    
          Console.WriteLine("WorkerThreads: {0}, CompletionPortThreads: {1}", workerThreads, completionPortThreads)
          Thread.Sleep(10000)
          Dim url As String = "http://www.msn.com"
          Dim myHttpWebRequest As HttpWebRequest
          Dim myHttpWebResponse As HttpWebResponse = Nothing
          ' Creates an HttpWebRequest for the specified URL. 
          myHttpWebRequest = CType(WebRequest.Create(url), HttpWebRequest)
          'Sends the HttpWebRequest, and waits for a response.
          myHttpWebResponse = CType(myHttpWebRequest.GetResponse(), HttpWebResponse)
          myHttpWebResponse.Close()
       End Sub
    End Module
  5. On the Debug menu, click Start to run the application. After the available WorkerThreads reaches 0, you receive the error message that is listed in the "Symptoms" section.

REFERENCES

For more information, visit the following Microsoft Web sites:

Modification Type:MajorLast Reviewed:5/15/2003
Keywords:kbNameSpace kbweb kbXML kbWNet kberrmsg kbConfig kbDev kbThread kbprb KB815637 kbAudDeveloper