调用HttpClient.GetAsync时出错:底层连接已关闭

时间:2015-05-19 17:48:38

标签: asp.net asynchronous asp.net-web-api

我有一个asp.net MVC网站正在使用rest api来接收它的数据。我使用异步任务来执行请求,因为每个页面上可能有很多。经过一段时间的正常运行后,网站在尝试接收数据时出现了以下错误。

基础连接已关闭:发送时发生意外错误。

我读到这可能是由于web.config上的maxconnection设置,但增加这似乎并没有太大的区别。

我还使用缓存来减少api的负载。该任务被缓存,以便稍后使用。

我发现解决此问题的唯一方法是回收应用程序池。任何帮助将不胜感激。

/* 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>());
    }
  }
}

2 个答案:

答案 0 :(得分:3)

这是错误的,

  

缓存任务,以便稍后使用。

您应该缓存结果,而不是任务。在首次执行结束时,您的HttpClient已关闭,当您尝试检索缓存任务时,它将无效。

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>());
    }
  }
}

答案 1 :(得分:0)

阿卡什可能是对的。 但似乎或多或少与应用程序池的连接问题。设置连接限制0以使其在应用程序池中无限制。 在代码中有一个finally块,

gc.collect();

要调用的垃圾收集方法,以删除未使用的连接以为其他连接腾出空间。