Asynchronous lambda expression

Hi

I share this simple article to show you some code about a TCache async method. I encountered this exception: Unable to convert a async lambda expression in Func.

The previows signature was :T Get(string cacheKeyName, int cacheTimeOutSeconds, Func<T> func); It is a generic method.

This method takes 3 arguments: 

cacheKeyName: the name of the item in cache

cacheTimeOutSeconds: the expiration policy.

func: the delegate that you can use to load the data from database if the cache object doesn't.

Get Retrieves the specified item from the Cache.

As you can see here, this method is not asynchronous, it is synchronous. Our goal is to make it an asynchronous operation with Task<T>

1) First, add an interface to your project and change the previous signature as below,  ITCache.cs, 

x
 
1
using System;
2
using System.Threading.Tasks;
3
4
namespace Custom.TCache.Web
5
{
6
    public interface ITCache<T>
7
    {
8
        Task<T> Get(string cacheKeyName, int cacheTimeOutSeconds, Func<Task<T>> func);
9
    }  
10
}


2)  Now create a class  TCacheProviderInternal  that implements ITCache<T>  and past the code below

33
 
1
using System;
2
using System.Threading.Tasks;
3
using System.Web;
4
5
namespace Custom.TCache.Web
6
{
7
    public class TCacheProviderInternal<T> : ITCache<T>
8
    {
9
        internal static readonly object Locker = new object();
10
11
        public Task<T> Get(string cacheName,int cacheTimeOutSeconds,Func<Task<T>> func)
12
        {
13
            var obj = HttpContext.Current.Cache.Get(cacheName);
14
            if (obj != null)
15
            {
16
                return (Task<T>)obj;
17
            }
18
19
            lock (Locker)
20
            {
21
                if (obj == null)
22
                {
23
                    obj = func();
24
                    HttpContext.Current.Cache.Insert(cacheName, obj, null,
25
                        DateTime.Now.Add(new TimeSpan(0, 0, cacheTimeOutSeconds)),
26
                        TimeSpan.Zero);
27
                }
28
                return (Task<T>)obj;
29
            }
30
        }
31
32
    }
33
}

- HttpContext.Current.Cache.Get(cacheName) gets the specified item "cacheName" in cache.

- obj =func() get the result of the delegate function, may be a collection of item, or a item.

HttpContext.Current.Cache.Insert(cacheName, obj, null, DateTime.Now.Add(new TimeSpan(0, 0, cacheTimeOutSeconds)), TimeSpan.Zero) inserts the obj in cache with an expiration policy.

(Task<T>)obj. We cast obj as a task object.


3) Then add a new class TCacheProvider  to your project and past the code below.

14
 
1
using System;
2
using System.Threading.Tasks;
3
4
namespace Custom.TCache.Web
5
{
6
    public class TCacheProvider<T>
7
    {
8
        public Task<T> Get(string cacheKeyName, int cacheTimeOutSeconds, Func<Task<T>> func)
9
        {
10
            return new TCacheProviderInternal<T>().Get(
11
                cacheKeyName,cacheTimeOutSeconds,func);
12
        }
13
    }
14
}


Now we can use our generic method.

In the sample we got an item in cache with: the specified name "all-tenants-cache-name". the expiration policiy is set to 30 s and the asynchronous lambda expression async()=>{}.

6
 
1
string cacheName = "all-tenants-cache-name";
2
int cacheTimeOutSeconds = 30;
3
List<Tenant> tenants = await new TCacheProvider<List<Tenant>>().Get(cacheName, cacheTimeOutSeconds,async () =>{
4
                                           //here some asynchronous methods for the delegate
5
                                           //please return something here
6
                                        });

For more share join in me on my gist here