Wiz
Wiz

Reputation: 307

GetRequestStream() is throwing time out exception when posting data to HTTPS url

I'm calling an API hosted on Apache server to post data. I'm using HttpWebRequest to perform POST in C#.

API has both normal HTTP and secure layer (HTTPS) PORT on the server. When I call HTTP URL it works perfectly fine. However, when I call HTTPS it gives me time-out exception (at GetRequestStream() function). Any insights? I'm using VS 2010, .Net framework 3.5 and C#. Here is the code block:

string json_value = jsonSerializer.Serialize(data);


        HttpWebRequest request = (HttpWebRequest)System.Net.WebRequest.Create("https://server-url-xxxx.com");
        request.Method = "POST";
        request.ProtocolVersion = System.Net.HttpVersion.Version10;
        request.ContentType = "application/x-www-form-urlencoded";

        byte[] buffer = Encoding.ASCII.GetBytes(json_value);
        request.ContentLength = buffer.Length;
        System.IO.Stream reqStream = request.GetRequestStream();
        reqStream.Write(buffer, 0, buffer.Length);
        reqStream.Close();

EDIT: The console program suggested by Peter works fine. But when I add data (in JSON format) that needs to be posted to the API, it throws out operation timed out exception. Here is the code that I add to console based application and it throws error.

byte[] buffer = Encoding.ASCII.GetBytes(json_value);
request.ContentLength = buffer.Length;

Upvotes: 18

Views: 35785

Answers (5)

FunRob
FunRob

Reputation: 21

I ran into this, too. I wanted to simulate hundreds of users with a Console app. When simulating only one user, everything was fine. But with more users came the Timeout exception all the time.

Timeout occurs because by default the ConnectionLimit=2 to a ServicePoint (aka website). Very good article to read: https://venkateshnarayanan.wordpress.com/2013/04/17/httpwebrequest-reuse-of-tcp-connections/

What you can do is:

1) make more ConnectionGroups within a servicePoint, because ConnectionLimit is per ConnectionGroups.

2) or you just simply increase the connection limit.

See my solution:

private HttpWebRequest CreateHttpWebRequest<U>(string userSessionID, string method, string fullUrl, U uploadData)
{
    HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(fullUrl);
    req.Method = method; // GET PUT POST DELETE
    req.ConnectionGroupName = userSessionID;  // We make separate connection-groups for each user session. Within a group connections can be reused.
    req.ServicePoint.ConnectionLimit = 10;    // The default value of 2 within a ConnectionGroup caused me always a "Timeout exception" because a user's 1-3 concurrent WebRequests within a second.
    req.ServicePoint.MaxIdleTime = 5 * 1000;  // (5 sec) default was 100000 (100 sec).  Max idle time for a connection within a ConnectionGroup for reuse before closing
    Log("Statistics: The sum of connections of all connectiongroups within the ServicePoint: " + req.ServicePoint.CurrentConnections; // just for statistics

    if (uploadData != null)
    {
        req.ContentType = "application/json";
        SerializeToJson(uploadData, req.GetRequestStream());
    }
    return req;
}

/// <summary>Serializes and writes obj to the requestStream and closes the stream. Uses JSON serialization from System.Runtime.Serialization.</summary>        
public void SerializeToJson(object obj, Stream requestStream)
{
    DataContractJsonSerializer json = new DataContractJsonSerializer(obj.GetType());
    json.WriteObject(requestStream, obj);            
    requestStream.Close();
}

Upvotes: 2

J.C. Gras
J.C. Gras

Reputation: 5442

Try this:

    WebRequest req = WebRequest.Create("https://server-url-xxxx.com");
    req.Method = "POST";
    string json_value = jsonSerializer.Serialize(data); //Body data
    ServicePointManager.Expect100Continue = false;
    using (var streamWriter = new StreamWriter(req.GetRequestStream()))
    {
        streamWriter.Write(json_value);
        streamWriter.Flush();
        streamWriter.Close();
    }
    HttpWebResponse resp = req.GetResponse() as HttpWebResponse;
    Stream GETResponseStream = resp.GetResponseStream();
    StreamReader sr = new StreamReader(GETResponseStream);
    var response = sr.ReadToEnd(); //Response
    resp.Close(); //Close response
    sr.Close(); //Close StreamReader

And review the URI:

  • Reserved characters. Send reserved characters by the URI can bring problems ! * ' ( ) ; : @ & = + $ , / ? # [ ]

  • URI Length: You should not exceed 2000 characters

Upvotes: 4

Peter
Peter

Reputation: 7804

I don't know if this will help you with your specific problem but you should consider Disposing some of those objects when you are finished with them. I was doing something like this recently and wrapping stuff up in using statements seems to clean up a bunch of timeout exceptions for me.

            using (var reqStream = request.GetRequestStream())
            {
                if (reqStream == null)
                {
                    return;
                }

              //do whatever

            }

also check these things

  • Is the server serving https in your local dev environment?
  • Have you set up your bindings *.443 (https) properly?
  • Do you need to set credentials on the request?
  • Is it your application pool account accessing the https resources or is it your account being passed through?
  • Have you thought about using WebClient instead?

    using (WebClient client = new WebClient())
        {               
            using (Stream stream = client.OpenRead("https://server-url-xxxx.com"))
            using (StreamReader reader = new StreamReader(stream))
            {
                MessageBox.Show(reader.ReadToEnd());
            }
        }
    

EDIT:

make a request from console.

internal class Program
{
    private static void Main(string[] args)
    {
        new Program().Run();
        Console.ReadLine();
    }

    public void Run()
    {

       var request = (HttpWebRequest)System.Net.WebRequest.Create("https://server-url-xxxx.com");
        request.Method = "POST";
        request.ProtocolVersion = System.Net.HttpVersion.Version10;
        request.ContentType = "application/x-www-form-urlencoded";

        using (var reqStream = request.GetRequestStream())
        {
            using(var response = new StreamReader(reqStream )
            {
              Console.WriteLine(response.ReadToEnd());
            }
        }
    }
}

Upvotes: 11

DDRider62
DDRider62

Reputation: 833

I ran into the same issue. It seems like it is solved for me. I went through all my code making sure to invoke webResponse.Close() and/or responseStream.Close() for all my HttpWebResponse objects. The documentation indicates that you can close the stream or the HttpWebResponse object. Calling both is not harmful, so I did. Not closing the responses may cause the application to run out of connections for reuse, and this seems to affect the HttpWebRequest.GetRequestStream as far as I can observe in my code.

Upvotes: 16

seUser
seUser

Reputation: 1103

You may want to set timeout property, check it here http://www.codeproject.com/Tips/69637/Setting-timeout-property-for-System-Net-WebClient

Upvotes: 1

Related Questions