缓存来自ASP.NET中的异步方法

mar*_*vpc 3 c# asp.net asp.net-mvc caching asynchronous

我有一个简单的MVC控制器,我做了异步,它使用await Task.WhenAll从Web服务获取数据.我想缓存这些调用的结果,所以我不必一直调用API.当我得到响应时,我在视图控制器中缓存结果,但理想情况下我想要调用API的方法来处理缓存.问题是该方法无法访问结果,因为它是异步的,只返回一个任务.

是否可以使用另一种方法在结果返回后缓存结果?

public async Task<ActionResult> Index()
{
    // Get data asynchronously
    var languagesTask = GetDataAsync<List<Language>>("languages");
    var currenciesTask = GetDataAsync<List<Currency>>("currencies");

    await Task.WhenAll(languagesTask, currenciesTask);


    // Get results
    List<Language> languages = languagesTask.Result;
    List<Currency> currencies = currenciesTask.Result;


    // Add results to cache
    AddToCache("languages", languages);
    AddToCache("currencies", currencies);


    // Add results to view and return
    ViewBag.languages = languages;
    ViewBag.currencies = currencies;

    return View();
}

public async Task<T> GetDataAsync<T>(string operation)
{
    // Check cache for data first
    string cacheName = operation;

    var cacheData = HttpRuntime.Cache[cacheName];

    if (cacheData != null)
    {
        return (T)cacheData;
    }


    // Get data from remote api
    using (HttpClient client = new HttpClient())
    {
        client.BaseAddress = new Uri("https://myapi.com/");

        var response = await client.GetAsync(operation);

        // Add result to cache
        //...

        return (await response.Content.ReadAsAsync<T>());
    }
}
Run Code Online (Sandbox Code Playgroud)

Ste*_*ary 9

只要缓存实现在内存中,您就可以自己缓存任务而不是任务结果:

public Task<T> GetDataAsync<T>(string operation)
{
  // Check cache for data first
  var task = HttpRuntime.Cache[operation] as Task<T>;
  if (task != null)
    return task;

  task = DoGetDataAsync(operation);
  AddToCache(operation, task);
  return task;
}

private async Task<T> DoGetDataAsync<T>(string operation)
{
  // Get data from remote api
  using (HttpClient client = new HttpClient())
  {
    client.BaseAddress = new Uri("https://myapi.com/");
    var response = await client.GetAsync(operation);
    return (await response.Content.ReadAsAsync<T>());
  }
}
Run Code Online (Sandbox Code Playgroud)

这种方法的另一个好处是,如果多个HTTP请求尝试获取相同的数据,它们实际上将共享任务本身.所以它共享实际的异步操作而不是结果.

但是,这种方法的缺点Task<T>是不可序列化,因此如果您使用自定义磁盘备份缓存或共享缓存(例如,Redis),则此方法将无法工作.