IDbAsyncEnumerable not implemented

I am trying to make a FakeDbContext with a FakeDbSet for unit testing.

But I get the following error (see below). I am extending DbSet so normally IDbAsyncEnumerable should be implemented. And when I implement it, it says that it has no use.

Exception:

System.InvalidOperationException: The source IQueryable doesn't implement IDbAsyncEnumerable. Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations. For more details see http://go.microsoft.com/fwlink/?LinkId=287068.

FakeDbSet class:

public abstract class FakeDbSet<TEntity> : DbSet<TEntity>, IEnumerable<TEntity>, IQueryable, IDbAsyncEnumerable<TEntity> where TEntity : Entity, new()
{
    #region Private Fields
    private readonly ObservableCollection<TEntity> _items;
    private readonly IQueryable _query;
    #endregion Private Fields

    protected FakeDbSet()
    {
        _items = new ObservableCollection<TEntity>();
        _query = _items.AsQueryable();
    }

    public Expression Expression { get { return _query.Expression; } }

    public Type ElementType { get { return _query.ElementType; } }

    public IQueryProvider Provider { get { return _query.Provider; } }

    public override TEntity Add(TEntity entity)
    {
        _items.Add(entity);
        return entity;
    }

    public override TEntity Remove(TEntity entity)
    {
        _items.Remove(entity);
        return entity;
    }

    public override TEntity Attach(TEntity entity)
    {
        switch (entity.ObjectState)
        {
            case ObjectState.Modified:
                _items.Remove(entity);
                _items.Add(entity);
                break;

            case ObjectState.Deleted:
                _items.Remove(entity);
                break;

            case ObjectState.Unchanged:
            case ObjectState.Added:
                _items.Add(entity);
                break;

            default:
                throw new ArgumentOutOfRangeException();
        }
        return entity;
    }

    public override TEntity Create() { return new TEntity(); }

    public override TDerivedEntity Create<TDerivedEntity>() { return Activator.CreateInstance<TDerivedEntity>(); }

    public override ObservableCollection<TEntity> Local { get { return _items; } }

    IEnumerator<TEntity> IEnumerable<TEntity>.GetEnumerator()
    {
        return _items.GetEnumerator();
    }

    Type IQueryable.ElementType
    {
        get { return _items.AsQueryable().ElementType; }
    }

    Expression IQueryable.Expression
    {
        get { return _items.AsQueryable().Expression; }
    }

    IQueryProvider IQueryable.Provider
    {
        get { return _items.AsQueryable().Provider; }
    }

Here is a gist with the code. In the last file in the gist, that is where the error happens. Gist code


Solution 1:

In my case the exception was caused by using the wrong ToListAsync extension.

It came from:

using System.Data.Entity;

instead of

using Microsoft.EntityFrameworkCore;

Changing the namespace fixed the error.

Solution 2:

Your scenario is explicitly mentioned in the link provided with the exception message (http://go.microsoft.com/fwlink/?LinkId=287068). The missing ingredient is the IDbAsyncQueryProvider that you should return from your Provider property.

Just navigate through the link to arrive at the boilerplate implementation.

Little I can add, I'll just quote the essential phrase:

In order to use asynchronous queries we need to do a little more work. If we tried to use our Moq DbSet with the GetAllBlogsAsync method we would get the following exception:

System.InvalidOperationException: The source IQueryable doesn't implement IDbAsyncEnumerable. Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations. For more details see http://go.microsoft.com/fwlink/?LinkId=287068.

In order to use the async methods we need to create an in-memory DbAsyncQueryProvider to process the async query. Whilst it would be possible to setup a query provider using Moq, it is much easier to create a test double implementation in code. The code for this implementation is as follows:

etc...

Solution 3:

I renamed the example test classes from here to remove the word Test since they are useful outside of testing:

  • DbAsyncEnumerable
  • DbAsyncEnumerator<T>
  • DbAsyncQueryProvider<TEntity>

Then I added the extension class below so you can now just do ...

var data = new List<Blog> 
{ 
    new Blog { Name = "BBB" }, 
    new Blog { Name = "ZZZ" }, 
    new Blog { Name = "AAA" }, 
}.AsAsyncQueryable();   // <<== new extension method

This is not only useful in unit tests but also when you want to implement an IQueryable<T> interface that either returns an async database query or in memory data that you can subsequently safely call as query.ToAsyncArray().

public static class AsyncQueryableExtensions
{
    public static IQueryable<TElement> AsAsyncQueryable<TElement>(this IEnumerable<TElement> source)
    {
        return new DbAsyncEnumerable<TElement>(source);
    }

    public static IDbAsyncEnumerable<TElement> AsDbAsyncEnumerable<TElement>(this IEnumerable<TElement> source)
    {
        return new DbAsyncEnumerable<TElement>(source);
    }

    public static EnumerableQuery<TElement> AsAsyncEnumerableQuery<TElement>(this IEnumerable<TElement> source)
    {
        return new DbAsyncEnumerable<TElement>(source);
    }

    public static IQueryable<TElement> AsAsyncQueryable<TElement>(this Expression expression)
    {
        return new DbAsyncEnumerable<TElement>(expression);
    }

    public static IDbAsyncEnumerable<TElement> AsDbAsyncEnumerable<TElement>(this Expression expression)
    {
        return new DbAsyncEnumerable<TElement>(expression);
    }

    public static EnumerableQuery<TElement> AsAsyncEnumerableQuery<TElement>(this Expression expression)
    {
        return new DbAsyncEnumerable<TElement>(expression);
    }
}