Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# HttpClient - can I force close the connection?

We are seeing an issue where a customer is hitting our API and cancelling the request before it completes. We believe that they are also closing the connection so the requests are not getting written to the IIS logs. I'm trying to create a runner to duplicate this behavior. What I can't figure out is how can I force close the connection so that the server cannot send data back?

Here is my current code:

 private static async Task RunMe()
    {

        var cts = new CancellationTokenSource();
        cts.CancelAfter(5000);

        using (var client = new HttpClient())
        {
            try
            {
                client.DefaultRequestHeaders.ConnectionClose = true;
                client.DefaultRequestHeaders.Add("x-apikey", "some key");
                Console.WriteLine("making request");
                using (var response = await client.GetAsync("https://foo.com/api/apitest/testcancel", cts.Token))
                {
                    var result = await response.Content.ReadAsStringAsync();
                    Console.WriteLine($"Request completed: {result}");
                }
            }
            finally
            {                    
                client.CancelPendingRequests();
                Console.WriteLine("about to dispose the client");
                client.Dispose();
            }
        }
    }
}

The code correctly cancels the request after 5 seconds but IIS still seem to send back data after the API call completes (set to 10 seconds).

How can I close the connection so that IIS cannot send back any data after my 5s timeout?

like image 260
jhilden Avatar asked Sep 06 '25 18:09

jhilden


2 Answers

I was finally able to duplicate the problem by using raw sockets, which is a lot of work. The way to get IIS to log the cancelled requests is to do the following in the code below:

  1. do NOT send Connection: Close
  2. do NOT call Socket.Dispose()

Here is the final working code, hopefully someone else will find this useful:

private static void SocketTime(int readTimeout, Random random)
        {
            var ip = IPAddress.Parse("127.0.0.1");
            const int hostPort = 80;

            var hostep = new IPEndPoint(ip, hostPort);
            var sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            sock.Connect(hostep);
            var uniqueID = random.Next().ToString();
            var get = $"GET http://localhost/api/apitest/testcancel/{uniqueID} HTTP/1.1\r\n" +
                      "x-apikey: somekey\r\n" +
                      "Host: foo.com\r\n" +
                      "Connection: Close\r\n" +
                      "\r\n";


            var getBytes = Encoding.UTF8.GetBytes(get);
            sock.ReceiveTimeout = readTimeout;
            sock.Send(getBytes);

            var responseData = new byte[1024];
            try
            {
                var bytesRead = sock.Receive(responseData);
                var responseString = new StringBuilder();
                while (bytesRead != 0)
                {
                    responseString.Append(Encoding.ASCII.GetChars(responseData), 0, bytesRead);
                    bytesRead = sock.Receive(responseData);
                }
                Console.WriteLine($"SUCCESS => Unique ID = {uniqueID}, Timeout = {readTimeout}");
            }
            catch (SocketException e)
            {
                if (e.SocketErrorCode == SocketError.TimedOut)
                {
                    Console.WriteLine($"FAIL => Unique ID = {uniqueID}, Timeout = {readTimeout}");
                }
                else
                {
                    Console.WriteLine("UNHNALDED ERROR: " + e.Message);
                }

            }
            finally
            {
                sock.Dispose();
            }
        }
like image 116
jhilden Avatar answered Sep 09 '25 23:09

jhilden


You are probably hit by a very low timeout setting. If you set it to a sufficiently short amount of time, the client will close the connection although the server still tries to return data.

If this doesn't reproduce the problem you could also look into concurrency and the property 'UseNagleAlgorithm' on the servicepoint manager. This property being true attempts to pigiback several small http requests in the same TCP package. It is a band with saver, but causes client timeouts as the os delays sending data through the socket until it has gathered enough data.

like image 27
faester Avatar answered Sep 09 '25 22:09

faester