Question
How to configure the TCP timeout for a single WebRequest?
Context
According to the docs, WebRequest.Timeout:
The length of time, in milliseconds, until the request times out, or the value Timeout.Infinite to indicate that the request does not time out. The default value is defined by the descendant class.
Requesting web resource from an non-existent endpoint (IIS without service bindings on the requested port) fails with a different and constant timeout of about 21 seconds.
According to this serverfault answer this appears to be a connect TCP timeout.
Sample Code
 public static async Task<string> WebRequestToString(string requestUri, int timeoutMilliseconds)
 {
     var request = WebRequest.Create(requestUri) as HttpWebRequest;
     request.KeepAlive = false;
     request.Timeout = timeoutMilliseconds;
     request.ReadWriteTimeout = timeoutMilliseconds;
     using (var response = await request.GetResponseAsync() as HttpWebResponse)
     {
         // Get the response stream
         using (var reader = new StreamReader(response.GetResponseStream()))
         {
             var responseBody = await reader.ReadToEndAsync();
             return responseBody;
         }
     }
 }
 static void Main(string[] args)
 {
     string uri = "http://10.15.1.24:8081/thiservicedoesnotexist/";
     int timeoutMilliseconds = 10;
     Stopwatch sw = new Stopwatch();
     sw.Start();
     try
     {
         WebRequestToString(uri, timeoutMilliseconds).Wait();
     }
     catch (AggregateException ex)
     {
         Console.WriteLine(ex.ToString());
     }
     sw.Stop();
     Console.WriteLine("Elaped {0}ms", sw.ElapsedMilliseconds);
     Console.ReadKey();
 }
Example Output
  System.AggregateException: One or more errors occurred. ---> System.Net.WebExcep
  tion: Unable to connect to the remote server ---> System.Net.Sockets.SocketExcep
  tion: A connection attempt failed because the connected party did not properly r
  espond after a period of time, or established connection failed because connecte
  d host has failed to respond 10.15.1.24:8081
     at System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)
     at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Sock
  et s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state,
  IAsyncResult asyncResult, Exception& exception)
     --- End of inner exception stack trace ---
     at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
     at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar,
  Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchron
  ization)
  --- End of stack trace from previous location where exception was thrown ---
     at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
     at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNot
  ification(Task task)
     at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
     at TimeoutTests.Program.<WebRequestToString>d__0.MoveNext() in \\vmware-host\
  shared folders\Documents\Visual Studio 2012\Projects\TimeoutTests\TimeoutTests\P
  rogram.cs:line 20
     --- End of inner exception stack trace ---
     at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceled
  Exceptions)
     at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationTo
  ken cancellationToken)
     at System.Threading.Tasks.Task.Wait()
     at TimeoutTests.Program.Main(String[] args) in \\vmware-host\shared folders\D
  ocuments\Visual Studio 2012\Projects\TimeoutTests\TimeoutTests\Program.cs:line 4
  0
  ---> (Inner Exception #0) System.Net.WebException: Unable to connect to the remo
  te server ---> System.Net.Sockets.SocketException: A connection attempt failed b
  ecause the connected party did not properly respond after a period of time, or e
  stablished connection failed because connected host has failed to respond 10.15.
  1.24:8081
     at System.Net.Sockets.Socket.EndConnect(IAsyncResult asyncResult)
     at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Sock
  et s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state,
  IAsyncResult asyncResult, Exception& exception)
     --- End of inner exception stack trace ---
     at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
     at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar,
  Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchron
  ization)
  --- End of stack trace from previous location where exception was thrown ---
     at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
     at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNot
  ification(Task task)
     at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
     at TimeoutTests.Program.<WebRequestToString>d__0.MoveNext() in \\vmware-host\
  shared folders\Documents\Visual Studio 2012\Projects\TimeoutTests\TimeoutTests\P
  rogram.cs:line 20<---
  Elaped 21169ms
 
     
    