Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error calling HttpClient.GetAsync: The underlying connection was closed

I have an asp.net MVC website which is consuming a rest api to receive it's data. I'm using asynchronous tasks to perform the requests as there can be many on each page. After a while of uptime the website has been throwing the following error when trying to receive data.

The underlying connection was closed: An unexpected error occurred on a send.

I read that this could be due to the maxconnection settings on the web.config but increasing this doesn't seem to make much difference.

I'm also using caching to reduce the load on the api. The task is cached so the result can be used later.

The only way I've found to fix this is by recycling the application pool. Any help would be appreciated.

/* Code from page_load */

var currenciesTask = ApiClient.GetAsync<CurrencyListWrapper>("currencies");
var blogArticleTask = ApiClient.GetAsync<BlogArticleListWrapper>("blog/articles", "limit=10");
var seoPageTask = ApiClient.GetAsync<SEOPageListWrapper>("seopages");

await Task.WhenAll(currenciesTask, blogArticleTask, seoPageTask);


/* Code from data access later */

public class ApiClient : HttpClient
{
  public static Task<T> GetAsync<T>(string operation, string query = null, bool cache = true)
  {
    // Check if task is in cache
    string cacheName = null;

    if (cache)
    {
      cacheName = String.Format("{0}_{1}_{2}", operation, query ?? String.Empty, App.GetLanguage());

      var cachedTask = HttpRuntime.Cache[cacheName];

      if (cachedTask != null)
      {
        return (Task<T>)cachedTask;
      }

    }

    // Get data task
    var task = GetAsyncData<T>(operation, query);

    // Add to cache if required
    if (task != null && cache)
    {
      App.AddToCache(cacheName, task);
    }

    return task;
  }

  public static async Task<T> GetAsyncData<T>(string operation, string query = null)
  {
    using (ApiClient client = new ApiClient())
    {
      string url;

      if (query != null)
      {
        url = String.Format("{0}?{1}", operation, query);
      }
      else
      {
        url = String.Format("{0}", operation);
      }

      var response = await client.GetAsync(url);

      return (await response.Content.ReadAsAsync<T>());
    }
  }
}
like image 854
Mark Clancy Avatar asked May 19 '15 17:05

Mark Clancy


1 Answers

This is wrong,

The task is cached so the result can be used later.

You are supposed to cache result, not the task. At end of first execution, your HttpClient is closed and when you try to retrieve cached task, it will not work.

public class ApiClient : HttpClient
{
  public static async Task<T> GetAsync<T>(string operation, string query = null, bool cache = true)
  {
    // Check if task is in cache
    string cacheName = null;

    if (cache)
    {
      cacheName = String.Format("{0}_{1}_{2}", operation, query ?? String.Empty, App.GetLanguage());

      T cachedResult = (T)HttpRuntime.Cache[cacheName];

      if (cachedResult!= null)
      {
        return Task.FromResult(cachedResult);
      }

    }

    // Get data task
    var result = await GetAsyncData<T>(operation, query);

    // Add to cache if required
    if (result != null && cache)
    {
      App.AddToCache(cacheName, result);
    }

    return result;
  }

  public static async Task<T> GetAsyncData<T>(string operation, string query = null)
  {
    using (ApiClient client = new ApiClient())
    {
      string url;

      if (query != null)
      {
        url = String.Format("{0}?{1}", operation, query);
      }
      else
      {
        url = String.Format("{0}", operation);
      }

      var response = await client.GetAsync(url);

      return (await response.Content.ReadAsAsync<T>());
    }
  }
}
like image 121
Akash Kava Avatar answered Sep 21 '22 20:09

Akash Kava