Reputation: 784
How to configure the TCP timeout for a single WebRequest?
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.
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();
}
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
Upvotes: 3
Views: 918
Reputation: 784
I ended up fixing this by creating a GetResponseAsync method extension based on approach and seems to work fine:
public static class WebRequestExtensions
{
public static async Task<WebResponse> GetResponseAsyncWithTimeout(this WebRequest request)
{
var timeoutCancellationTokenSource = new CancellationTokenSource();
var responseTask = request.GetResponseAsync();
var completedTask = await Task.WhenAny(responseTask, Task.Delay(request.Timeout, timeoutCancellationTokenSource.Token));
if (completedTask == responseTask)
{
timeoutCancellationTokenSource.Cancel();
return await responseTask;
}
else
{
request.Abort();
throw new TimeoutException("The operation has timed out.");
}
}
}
Upvotes: 1
Reputation: 7467
I am very doubtful that this timeout is actually the same as the TCP connection timeout. The documentation of the webrequest timeout is as follows :
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.
That is a timeout on the level of your request, ie HTTP. It might be that a connection to the server is establised but that creating the response takes a long time. Also that time can time out.
How the webrequest handles this and maps it on TCP is implementation dependent. A TCP timeout for connection establishment cannot be infinite.
I also read the following :
The Timeout property indicates the length of time, in milliseconds, until the request times out and throws a WebException. The Timeout property affects only synchronous requests made with the GetResponse method. To time out asynchronous requests, use the Abort method.
You are asynchronous!
Upvotes: 2