Async await IQueryable

Usage :

                var user = (await db.WishlistUsers.Where(u => u.ID == wishlistUser.ID).ExecuteAsync()).FirstOrDefault();
                if (user == null)
                    throw new ArgumentException("User not found...");

Source :

using System;
using System.Linq;
using System.Collections.Generic;
using System.Runtime.Remoting.Messaging;
using System.Threading.Tasks;

namespace Linqy
{
    public static class AsynchronousQueryExecutor
    {
        public static IEnumerable<T> Except<T, TKey>(this IEnumerable<T> items, IEnumerable<T> other,
                                                                            Func<T, TKey> getKey)
        {
            return from item in items
                   join otherItem in other on getKey(item)
                   equals getKey(otherItem) into tempItems
                   from temp in tempItems.DefaultIfEmpty()
                   where ReferenceEquals(null, temp) || temp.Equals(default(T))
                   select item;

        }

        public static Task<IEnumerable<T>> ExecuteAsync<T>(this IEnumerable<T> query)
        {
            TaskCompletionSource<IEnumerable<T>> tcs = new TaskCompletionSource<IEnumerable<T>>();
            Call<T>(query,
                (result) =>
                {
                    tcs.SetResult(result);
                },
                (exception) =>
                {
                    tcs.SetException(exception);
                });
            return tcs.Task;
        }

        private static void Call<T>(IEnumerable<T> query, Action<IEnumerable<T>> callback, Action<Exception> errorCallback)
        {
            Func<IEnumerable<T>, IEnumerable<T>> func =
                new Func<IEnumerable<T>, IEnumerable<T>>(InnerEnumerate<T>);
            IEnumerable<T> result = null;
            IAsyncResult ar = func.BeginInvoke(
                                query,
                                new AsyncCallback(delegate(IAsyncResult arr)
                                {
                                    try
                                    {
                                        result = ((Func<IEnumerable<T>, IEnumerable<T>>)((AsyncResult)arr).AsyncDelegate).EndInvoke(arr);
                                    }
                                    catch (Exception ex)
                                    {
                                        if (errorCallback != null)
                                        {
                                            errorCallback(ex);
                                        }
                                        return;
                                    }
                                    //errors from inside here are the callbacks problem
                                    //I think it would be confusing to report them
                                    callback(result);
                                }),
                                null);
        }

        private static IEnumerable<T> InnerEnumerate<T>(IEnumerable<T> query)
        {
            foreach (var item in query) //the method hangs here while the query executes
            {
                yield return item;
            }
        }
    }
}

Leave a comment