Search code examples
c#httphttpwebrequestgraphql

HttpListenerRequest read InputStream slow when using HttpClient or WebRequest


I have a HttpListener which is waiting for incoming requests. The curious thing is that when I send a request with the HttpClient or WebRequest class, the reading/decoding of the stream takes around 350ms, while sending the same request with Insomnia (https://insomnia.rest/) it only takes 500ticks!!

Can someone explain to me where is my fault?!

HttpClient

private readonly HttpClient _Client = new HttpClient();

private async void HttpClientMethod(string jsonContent)
{
    HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, _BaseUrl);

    message.Content = new StringContent(jsonContent);

    HttpResponseMessage result = await _Client.SendAsync(message);
    string content = await result.Content.ReadAsStringAsync();

    Console.WriteLine(content);
}

WebRequest Client

private string WebRequestMethod(string jsonContent)
{
    WebRequest request = WebRequest.Create(_BaseUrl);

    // Set the Method property of the request to POST.
    request.Method = "POST";
    // Create POST data and convert it to a byte array.
    string postData = jsonContent;
    byte[] byteArray = Encoding.UTF8.GetBytes(postData);
    // Set the ContentType property of the WebRequest.
    request.ContentType = "application/x-www-form-urlencoded";
    // Set the ContentLength property of the WebRequest.
    request.ContentLength = byteArray.Length;
    // Get the request stream.
    Stream dataStream = request.GetRequestStream();
    // Write the data to the request stream.
    dataStream.Write(byteArray, 0, byteArray.Length);
    // Close the Stream object.
    dataStream.Close();
    // Get the response.
    WebResponse response = request.GetResponse();
    // Display the status.
    Console.WriteLine(((HttpWebResponse)response).StatusDescription);
    // Get the stream containing content returned by the server.
    dataStream = response.GetResponseStream();
    // Open the stream using a StreamReader for easy access.
    StreamReader reader = new StreamReader(dataStream);
    // Read the content.
    string responseFromServer = reader.ReadToEnd();
    // Display the content.

    // Clean up the streams.
    reader.Close();
    dataStream.Close();
    response.Close();

    return responseFromServer;
}

Host

private void ReadInputStream(HttpListenerRequest request)
{
    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();
    string text;
    using (StreamReader reader = new StreamReader(request.InputStream, request.ContentEncoding))
    {
        text = reader.ReadToEnd();
    }
    stopwatch.Stop();
}

HttpClient | WebRequest

httpclient

Insomnia

insomnia

Insonmia Body | JSONContent

json

Sample Project

Just create a new Console App

Program.cs

using System;
using System.Net.Http;
using System.Threading.Tasks;

namespace ApiTest
{
    class Program
    {
        static readonly ApiHost _ApiHost = new ApiHost();
        static readonly HttpClient _Client = new HttpClient();

        static void Main(string[] args) => MainAsync(args).GetAwaiter().GetResult();

        static async Task MainAsync(string[] args)
        {
            _ApiHost.Start();
            Console.WriteLine("Host started");
            Console.ReadKey();

            string jsonContent ="{\"OperationName\":null,\"Query\":\"query {\\r\\n\\t                            hero{\\r\\n\\t\\t                            name,\\r\\n\\t\\t                            id\\r\\n\\t                            }\\r\\n\\t                            human(id: \\\"1\\\"){\\r\\n\\r\\n                                        homePlanet,\\r\\n                                        name\\r\\n\\r\\n                                    }\\r\\n                                }\",\"Variables\":null}";

            HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, new Uri("http://localhost:5000/"));
            message.Content = new StringContent(jsonContent);
            HttpResponseMessage result = await _Client.SendAsync(message);
            string content = await result.Content.ReadAsStringAsync();
            Console.WriteLine(content);
            Console.ReadKey();
        }
    }
}

ApiHost.cs

using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

namespace ApiTest
{
    public class ApiHost
    {
        public HttpListener Listener = new HttpListener();
        private bool _Stop;

        public void Start()
        {
            Listener.Prefixes.Add("http://+:5000/");
            Listener.Start();            
            Task.Run(() =>
            {
                Semaphore semaphore = new Semaphore(4, 4);
                while (!_Stop)
                {
                    semaphore.WaitOne();

                    Listener.GetContextAsync().ContinueWith(async (contextTask) =>
                    {
                        try
                        {
                            semaphore.Release();
                            HttpListenerContext context = await contextTask.ConfigureAwait(false);
                            Process(context);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex);
                            throw;
                        }
                    });
                }
            });
        }

        private void Process(HttpListenerContext ctx)
        {
            try
            {
                Stopwatch stopwatch = new Stopwatch();
                stopwatch.Start();
                string text;
                using (StreamReader reader = new StreamReader(ctx.Request.InputStream, ctx.Request.ContentEncoding))
                {
                    text = reader.ReadToEnd();
                }
                stopwatch.Stop();

                using (Stream output = ctx.Response.OutputStream)
                {
                    using (StreamWriter writer = new StreamWriter(output) { AutoFlush = true })
                    {
                        writer.Write(text);
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
    }
}

Question:

Why do I have 360ms when using the internal library. When I use Insomnia for example I don't have this delay!


Solution

  • Kaspersky was the problem. After stopping the application it is running without any problems!

    preview