Nil Pun
Nil Pun

Reputation: 17373

ASP.NET MVC3 how to wait for async call back and return result

Background:

I'm working on Cache warmup functionality to increase the performance on ASP.NET MVC Web by pre-loading the object in Cache before it's been requested.

I'm using Azure In-Role cache, which provided AddItemLevelCallback function when Cache is updated/removed/added etc. I've shared the code logic below.

Problem:

The AddItemLevelCallback on NotifyOnceCacheIsUpdated shown in the code snippet below doesn't get invoked straight away until Item is added/updated. The request will need to wait. But the problem is the the AddItemLevelCallback is async and KickOffWarmUpCache on DAL may return before the actual item is added/updated.

What would be the elegant way to handle this scenario where KickOffWarmUpCache only returns the result to the caller only after AddItemLevelCallback is triggered.

Technology: MVC3, .NET Framework 4.5

Code Sample:

CONTROLLER

 public void WarmUpCache(string id)
 {
    var userInfo = BLL.KickOffWarmUpCache(string id);
 }

BLL

public UserInfo KickOffWarmUpCache(string id)
{
    return DAL.KickOffWarmUpCache(string id)
}

DAL

public UserInfo KickOffWarmUpCache(string id)
{
    UserInfo userInfo = new UserInfo();
    //If Status = Progress
    if (cache.Get(id).Status == "Progress")
    {
        NotifyOnceCacheIsUpdated(id,(result)=>
        {
            userInfo=result.userInfo;
        });
    }else{
           userInfo=Cache.Get(id);
     }

      //This needs to wait for until callback is triggered and userInfo is populated
      return userInfo;
}

UTIL

public void NotifyOnceCacheIsUpdated(string cacheKey, Action<T> callback)
 {
    DataCacheOperations allCacheOperations = DataCacheOperations.ReplaceItem | DataCacheOperations.AddItem ;
    _ndItemLvlAllOps = cache.AddItemLevelCallback(cacheKey, allCacheOperations,
                     (CacheName, cacheRegion, cacheKey, itemVersion, OperationId, nd) =>
                        {
                            cachedData = cache.Get(cacheKey);
                            callback(cachedData);
                        });
        }

Upvotes: 0

Views: 796

Answers (1)

Aron
Aron

Reputation: 15772

public Task<UserInfo> KickOffWarmUpCache(string id)
{

    //If Status = Progress
    if (cache.Get(id).Status == "Progress")
    {
        var ret = new TaskCompletionSource<UserInfo>();
        NotifyOnceCacheIsUpdated(id,(result)=>
        {
            //complete the task.
            ret.SetResult(result.userInfo);
        });
        //return a Task...which the SetResult will complete.
        return ret.Task;
    }

    //Return a result synchronously
    return Task.FromResult(Cache.Get(id));
}

Upvotes: 1

Related Questions