Reputation: 5808
I have synchronous HttpHandler. I want to cache result of HttpClient.GetAsync and use it in my HttpHandler. I did it this way:
public static class CacheFacade
{
private static Cache Cache => HttpRuntime.Cache;
private const string CacheKey = "asynccache";
private static readonly object _lockObject = new object();
public static string GetStringFromCache()
{
if (Cache[CacheKey] == null)
{
lock(_lockObject)
{
if (Cache[CacheKey] == null)
{
InitCache();
}
}
//fallback here; I can use data from some synchronous source
return "init cache" + " - " + Thread.CurrentThread.ManagedThreadId;
}
var task = (Task<string>) Cache[CacheKey];
if (!task.IsCompleted)
{
//and fallback here too
return task.Status + " - " + DateTime.UtcNow + " - " + Thread.CurrentThread.ManagedThreadId;
}
return task.Result;
}
private static void InitCache()
{
var task = Task.Run(GetDataAsync);
Cache.Insert(CacheKey, task, null, DateTime.Now.Add(TimeSpan.FromSeconds(10)),
Cache.NoSlidingExpiration);
}
private static async Task<string> GetDataAsync()
{
using (var httpClient = new HttpClient())
{
await Task.Delay(TimeSpan.FromSeconds(2));
var res = await httpClient.GetAsync("http://www.google.com");
return res.StatusCode + " - " + DateTime.UtcNow + " - " + Thread.CurrentThread.ManagedThreadId;
}
}
}
It works. Does this approach have any disadvantages?
UPDATE: added lock with double check according to https://en.wikipedia.org/wiki/Double-checked_locking .
Upvotes: 1
Views: 167
Reputation: 171226
This is OK.
Note, that these cache items can only be stored in-process. You can't use an out-of-process cache because tasks cannot be serialized. You might or might not care about that.
In your fallback here; I can use data from some synchronous source
handling you can also block on the task (or await it if architecturally possible).
HTTP handlers support async processing using tasks as well. I believe you need a tiny helper/wrapper for that which is easy to write or available on the web.
Upvotes: 1