I use HttpClient to perform REST calls to remote server:
using (var response = httpClient.PostAsync(Url, content).Result)
{
// code
}
It works fine, but sometimes it returns strange error:
2014-07-28 12:04:40,098 (268795336) [114] ERROR -
System.AggregateException: One or more errors occurred. --->
System.Net.Http.HttpRequestException: An error occurred while sending
the request. ---> System.Net.WebException: The underlying connection
was closed: An unexpected error occurred on a send. --->
System.ArgumentOutOfRangeException: Count cannot be less than zero.
Parameter name: count
at System.Net.TlsStream.EndWrite(IAsyncResult asyncResult)
at System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar)
What could be the cause of the problem?
I guess the occasional problem might be caused by a deadlock. When we are using async methods, it is better to use await rather than Task.Result for the above reason. Do take a look at this link which discuss about best practices in asynchronous programming.
Related
i made a program, to retrieve some price from some website, it works pretty good, but if i let my application rest or idle for 1 or 2 minutes then when i want to run a price check againm it would throw an exception "an error occurred while sending the request" , i have tried everything i found in google, like adding SecurityProtocol, running it on a Task or using WebClient, but nothing works.
here is the function that retrieve my http code, i then extract the price from it.
HttpClient client = new HttpClient();
public async Task ListViewScanner(string URL, int SelectedItem)
{
string webData;
try
{
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12 |
System.Net.SecurityProtocolType.Tls11 |
System.Net.SecurityProtocolType.Tls;
using (HttpResponseMessage response = await client.GetAsync(URL))
{
response.EnsureSuccessStatusCode();
webData = await response.Content.ReadAsStringAsync(); //HERE MY CATCH GETS TRIGGERED
}
}
catch (HttpRequestException e)
{
MessageBox.Show($"Message :{e.Message} ");
webData = "ERROR";
}
}
I commented where i get the exception.
exceptions
SocketException: An existing connection was forcibly closed by the remote host
IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
WebException: The underlying connection was closed: An unexpected error occurred on a send.
HttpRequestException: An error occurred while sending the request.
Use a new instance of HttpClient every time, it's maybe related to the old instance that close the connection.
don't forge to use with a using statement to make sure that is destroyed when the call end.
This is the method where I am requesting post request but I am getting following error Basically I am consuming post method in the client side code **
error
** System.AggregateException
HResult=0x80131500
Message=One or more errors occurred.
Source=mscorlib
StackTrace:
at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
at System.Threading.Tasks.Task`1.get_Result()
at Client.team.AddTeam() in K:\LiveScoreSystemWebApi\Client\team.aspx.cs:line 259
at Client.team.GoBtn_Click(Object sender, EventArgs e) in K:\LiveScoreSystemWebApi\Client\team.aspx.cs:line 51
This exception was originally thrown at this call stack:
[External Code]
Inner Exception 1:
HttpRequestException: An error occurred while sending the request.
Inner Exception 2:
WebException: The underlying connection was closed: An unexpected error occurred on a receive.
Inner Exception 3:
IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
Inner Exception 4:
SocketException: An existing connection was forcibly closed by the remote host
**
----------
Code
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:44382/api/Team");
MediaTypeFormatter[] formatter = new MediaTypeFormatter[] { new JsonMediaTypeFormatter() };
HttpContent content = new ObjectContent<Team>(team1, formatter[0]);
HttpResponseMessage response = client.PostAsync(client.BaseAddress +"/insertTeam",content).Result;
I get an IOExection from the following code
public async Task Register(string handle)
{
// send register handle
using (NetworkStream stream = client.GetStream())
{
await RegisterHandle(stream);
var line = "hello world";
await SendMessage(stream, line);
}
}
public async Task SendMessage(NetworkStream stream, string message)
{
Console.WriteLine("SendMessage(" + message + ")");
await Async.Write(stream, message);
Console.WriteLine("End of SendMessage");
}
System.AggregateException: One or more errors occurred. (Unable to transfer data on the transport connection: An established connection was aborted by the software in your host machine.) ---> System.IO.IOException: Unable to transfer data on the transport connection: An established connection was aborted by the software in your host machine. ---> System.Net.Sockets.SocketException: An established connection was aborted by the software in your host machine
What can I do to fix this?
RegisterHandle just writes data then reads back; which works fine. However it fails when writing inside SendMessage.
Its actually all explained in detail in the docuemtnation
You need to try and check the exception messages, and if you have control over the connecting socket work out what it is closing on you. If none of the above you may have a network problem but i would go with the Occam's razor analysis first
NetworkStream.Write Method (Byte[], Int32, Int32)
IOException There was a failure while writing to the network.
-or-
An error occurred when accessing the socket. See the Remarks section
for more information.
Remarks
The Write method starts at the specified offset and sends size bytes
from the contents of buffer to the network. The Write method blocks
until the requested number of bytes is sent or a SocketException is
thrown. If you receive a SocketException, use the
SocketException.ErrorCode property to obtain the specific error code,
and refer to the Windows Sockets version 2 API error code
documentation in MSDN for a detailed description of the error.
Note
Check to see if the NetworkStream is writable by accessing the
CanWrite property. If you attempt to write to a NetworkStream that is
not writable, you will get an IOException. If you receive an
IOException, check the InnerException property to determine if it was
caused by a SocketException.
I've written an application that in part can download files from a specific web service. The code utilizes an HttpClient to make the calls. The problem is that occasionally I will get a failed request with the following exception message:
Unable to read data from the transport connection: The connection was closed.
I did run across these blog posts, in which the author had to revert the protocol version to 1.0, disable keep alive, and limit the number of service point connections:
http://briancaos.wordpress.com/2012/07/06/unable-to-read-data-from-the-transport-connection-the-connection-was-closed/
http://briancaos.wordpress.com/2012/06/15/an-existing-connection-was-forcibly-closed-by-the-remote-host/
I followed those instructions, as best I knew how and still got the error. I also made sure to keep a single instance of the HttpClient around (following the Singleton principle).
What is interesting is that when running Fiddler I've yet to get the error, which makes me think that there is something that can be done on the client side since Fiddler appears to be doing something to keep the connection alive (though the issue is so sporadic this may be a red herring).
A couple more notes:
The error invariably occurs in the middle of a download (never when initiating the request).
The file continues to download up to the point of failure (there are no extended pauses or delays first).
--UPDATE--
The error occurs on the following line:
responseTask.Wait(cancellationTokenSource.Token);
The following is the full exception:
System.AggregateException occurred HResult=-2146233088 Message=One
or more errors occurred. Source=mscorlib StackTrace:
at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
at Form1.StartDownload() in c:\Projects\Visual Studio 2012\Demo\Demo\Form1.cs:line 88 InnerException:
System.Net.Http.HttpRequestException
HResult=-2146233088
Message=Error while copying content to a stream.
InnerException: System.IO.IOException
HResult=-2146232800
Message=Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
Source=System
StackTrace:
at System.Net.ConnectStream.EndRead(IAsyncResult asyncResult)
at System.Net.Http.HttpClientHandler.WebExceptionWrapperStream.EndRead(IAsyncResult
asyncResult)
at System.Net.Http.Handlers.ProgressStream.EndRead(IAsyncResult
asyncResult)
at System.Net.Http.StreamToStreamCopy.BufferReadCallback(IAsyncResult ar)
InnerException: System.Net.Sockets.SocketException
HResult=-2147467259
Message=An existing connection was forcibly closed by the remote host
Source=System
ErrorCode=10054
NativeErrorCode=10054
StackTrace:
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
InnerException:
--UPDATE #2--
I thought I would try changing the completion option from 'content read' to 'headers read'. This also failed with the same exception, albeit in a different location (where the TODO comment is, reading the content stream).
--UPDATE #3--
I can confirm that the web service (which is hosted in IIS) is aborting the connections (the IIS logs show a win32 status code of 1236 - ERROR_CONNECTION_ABORTED). To try and narrow things down, the MinFileBytesPerSec metabase property was set to zero (on the off chance the client stopped pulling down data momentarily) and the connection is still being aborted. I've double checked all the timeouts and buffer sizes I can think of to no avail. Clawing at thin air at the moment. Any ideas would be appreciated.
Client Setup:
private void SetupClient()
{
// In case we're taxing the web server, limit the number
// connections we're allowed to make to one.
ServicePointManager.DefaultConnectionLimit = 1;
// Set up the progress handler so that we can keep track of the download progress.
_progressHandler = new ProgressMessageHandler();
_progressHandler.HttpReceiveProgress += ProgressHandler_HttpReceiveProgress;
// Create our HttpClient.
_client = HttpClientFactory.Create(_progressHandler);
_client.BaseAddress = new Uri("http://localhost");
_client.Timeout = TimeSpan.FromMinutes(30);
_client.DefaultRequestHeaders.TransferEncodingChunked = true;
}
Download Logic:
private void StartDownload()
{
// Create the request.
using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/Download"))
{
// Revert the protocol version and turn off keep alive in accordance with:
// http://briancaos.wordpress.com/2012/07/06/unable-to-read-data-from-the-transport-connection-the-connection-was-closed/
// http://briancaos.wordpress.com/2012/06/15/an-existing-connection-was-forcibly-closed-by-the-remote-host/
request.Version = new Version("1.0");
request.Headers.Add("Keep-Alive", "false");
// Set the cancellation token's timeout to 30 minutes.
int timeoutInMilliseconds = 30 * 60 * 1000;
using (CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(timeoutInMilliseconds))
{
// Making sure that the message isn't "complete" until everything is read in so we can cancel it at anytime.
Task<HttpResponseMessage> responseTask = _client.SendAsync(request, HttpCompletionOption.ResponseContentRead);
responseTask.Wait(cancellationTokenSource.Token);
using (HttpResponseMessage response = responseTask.Result)
{
if (!response.IsSuccessStatusCode)
{
throw new Exception("Request failed!");
}
Task<Stream> streamTask = response.Content.ReadAsStreamAsync();
using (Stream contentStream = streamTask.Result)
{
// TODO: Save to disk.
}
}
}
}
}
I'm using ReCAPTCHA in MVC4 application hosted in Azure cloud for a simple website with one registration form. We have about 100-120 successful registrations per hour currently. The problem is that I have hundreds of System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host errors in the logs, and then number keeps growing fast:
System.Net.Http.HttpRequestException: An error occurred while sending the request. --->
System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a receive. --->
System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. --->
System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
--- End of inner exception stack trace ---
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
at System.Net.Connection.ReadCallback(IAsyncResult asyncResult)
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)
--- End of inner exception stack trace ---
--- End of inner exception stack trace ---
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
at My.Web.Infrastructure.Filters.ValidateReCaptchaAttribute.OnActionExecuting(ActionExecutingContext filterContext) in My.Web\Infrastructure\Filters\ValidateReCaptchaAttribute.cs:line 49 --->
(Inner Exception #0) System.Net.Http.HttpRequestException: An error occurred while sending the request. --->
System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a receive. --->
System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. --->
System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
--- End of inner exception stack trace ---
I use attribute to validate captcha as follows (i deleted some non-important details):
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class ValidateReCaptchaAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var formValues = new[]
{
new KeyValuePair<string, string>("privatekey", ConfigurationProvider.ReCaptchaPrivateKey),
new KeyValuePair<string, string>("remoteip", remoteIp.ToString()),
new KeyValuePair<string, string>("challenge", challengeField),
new KeyValuePair<string, string>("response", responseField)
};
try
{
using (var client = HttpClientFactory.Create())
using (var data = new FormUrlEncodedContent(formValues))
using (var response = client.PostAsync("http://www.google.com/recaptcha/api/verify", data).Result)
{
var responseString = response.Content.ReadAsStringAsync().Result;
if (responseString.StartsWith("true") == false)
{
modelState.AddModelError(string.Empty, DisplayName.Validation_CaptchaMissing);
}
}
}
catch (Exception ex)
{
log4net.LogManager.GetLogger("WebLogger").Error(string.Format("ValidateReCaptcha failed on {0}/{1}. {2}", controller, action, formValuesRaw), ex);
modelState.AddModelError(string.Empty, DisplayName.Validation_CaptchaMissing);
}
}
}
it fails on var response = client.PostAsync() line. Not always. I was not able to reproduce it locally. But it fails pretty much for every user of the website - sometimes once, sometimes twice, sometimes more. Eventually they are able to register - as I said, I'm seeing more than 100 registrations per hour - but that results in 300-400 errors in the log table for that hour. I tried to register myself - and though I was 100% sure that I entered captcha correctly, I got validation error.
Any ideas? Does my validation attribute look okay? what can be other reasons?
Ah!.. fixed it by removing
using (var client = HttpClientFactory.Create())
line and creating HttpClient as singleton:
public class ValidateReCaptchaAttribute : ActionFilterAttribute
{
private static readonly HttpClient HttpClient = new HttpClient();
// rest of the code goes here...
as suggested by this SO answer