Maxim Tkachenko
Maxim Tkachenko

Reputation: 5808

ASP.NET: cache task and call its result in synchronous code

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

Answers (1)

usr
usr

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

Related Questions