title: HttpClient hangs on GetAsync when making many web requests to localhost
body: <p>I'm having the below issue when calling <code>api/Values/Test?times={x}</code>. The issue doesn't occur when <code>x</code> is 1, 2, ..., but the web request times out when it reaches 9, 10, and so on.
  As you can see, the <code>Test</code> endpoint will make a web request to <code>EndPoint</code> <code>x</code> times (excuse the pointless method bodies, they'll do more meaningful things in practice):</p>
  
  <pre><code>public class ValuesController:  System.Web.Http.ApiController
  {
      [HttpGet]
      public async Task&lt;object&gt; Test(int times)
      {
          var tasks = new List&lt;Task&lt;int&gt;&gt;();
          for (var i = 0; i &lt; times; i++)
          {
              //Make web request to the `EndPoint` method below
              var task = new ApiRequestBuilder&lt;int&gt;("https://localhost:44301/api/Values/EndPoint")
                  .GetAsync();
              tasks.Add(task);
          }
          return await Task.WhenAll(tasks.ToArray());
      } 
  
      [HttpGet]
      [CustomAuthorise]//This makes a web request to `AuthEndPoint` (below)
      public int EndPoint()
      {
          return 0;
      }
  
      [HttpGet]
      public bool AuthEndPoint()
      {
          return true;
      }
  }
  </code></pre>
  
  <p>(<strong>NB</strong> see below for what <code>ApiRequestBuilder</code> is)</p>
  
  <p>The problem, however, isn't <code>EndPoint</code> being hit <code>x</code> times, it's the <code>CustomAuthorise</code> attribute, which makes a further web request, that is the problem:</p>
  
  <pre><code>public class CustomAuthoriseAttribute : System.Web.Http.AuthorizeAttribute
  {
      public override async Task OnAuthorizationAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
      {
          var result = await this.AuthoriseAsync(actionContext);
          if (!result)
          {
              actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden);
          }
      }
  
      public virtual async Task&lt;bool&gt; AuthoriseAsync(HttpActionContext context)
      {
          //***********HANGING HERE************
          //var result= await new ApiRequestBuilder&lt;bool&gt;("https://www.example.com")
          var result= await new ApiRequestBuilder&lt;bool&gt;("https://localhost:44301/Values/AuthEndPoint")
              .GetAsync();
  
          return result;
      }
  }
  </code></pre>
  
  <p>As you can see, I've commented out the route <code>"https://www.example.com"</code>. When I set the url to something that isn't <code>localhost</code>, a can spam that web request (by setting <code>x</code> to a large number) however much I want. </p>
  
  <p><code>ApiRequestBuilder</code> is a helper for making web requests via a <code>System.Net.Http.HttpClient</code> (version <code>4.0.0.0</code>, .NETframework <code>v4.5.1</code>), that serializes the response to the generic type parameter you give it.</p>
  
  <pre><code>public class ApiRequestBuilder&lt;T&gt; 
  {
      protected string Url =&gt; Uri?.AbsoluteUri;
      protected Uri Uri;
      protected readonly HttpClient Client;
  
      public ApiRequestBuilder(string url) 
      {
          Uri = new Uri(url);
          var client = new HttpClient()
          {
              BaseAddress = this.Uri,
              //Set timeout so replicating this issue itn't a pain
              Timeout = TimeSpan.FromSeconds(5)
          };
          this.Client = client;       
      }
  
      public async Task&lt;T&gt; GetAsync()
      {
          var response = await this.Client.GetAsync(this.Url);
          var responseContent = await response.Content.ReadAsStringAsync();
          return JsonConvert.DeserializeObject&lt;T&gt;(responseContent);
      }
  }
  </code></pre>
  
  <p>Things I've tried: </p>
  
  <ul>
  <li><p>Have a <code>using</code> statement for each use of <code>HttpClient</code> in <code>ApiRequestBuilder</code> - still hangs.</p></li>
  <li><p>Await each <code>Task</code> in the for loop in <code>ValuesController.Test</code> - this works, but does not solve my problem, as in practice I'm trying to simulate concurrency for using my custom auth attribute.</p></li>
  </ul>
  
  <p>Potentially useful:</p>
  
  <ul>
  <li><p>I'm running local IIS on port <code>44301</code>, the maximum concurrent connections is massive - 4294967295.</p></li>
  <li><p>Like I said, changing the url from <code>localhost</code> to something like <code>example.com</code> when authorising, fixes the issue, which isolates the issue to something being wrong with my local setup</p></li>
  </ul>
  
  <p>Does anyone know why using web request in authorise attributes seems hang with concurrency using <code>localhost</code> rather than using a url out there in the big wide world?</p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>Running <code>netstat -n</code> at the point of hanging (I removed the timeout for this so I could look at what the TCP connections were doing). For every web request in progress that was seemingly blocked I had the following:</p>
  
  <pre><code>Proto  Local Address          Foreign Address        State
  TCP    [::1]:44301            [::1]:44728            CLOSE_WAIT
  TCP    [::1]:44728            [::1]:44301            FIN_WAIT_2
  </code></pre>
  
  <p>With the help of <a href="https://kb.iu.edu/d/ajmi" rel="nofollow noreferrer">this</a>, it seems like the server has asked the client to exit, the clients acknowledged it, but they're both hanging (client isn't closing?).</p>