Error with duck enumeration for IAsyncEnumerable in System.Interactive.Async - c#

I wonder why this code for IAsyncEnumerable<>
dynamic duckAsyncEnumerable = new int[0].ToAsyncEnumerable();
var duckAsyncEnumerator = duckAsyncEnumerable.GetEnumerator();
raises an exception:
'object' does not contain a definition for 'GetEnumerator'
Same code for IEnumerable<> works fine.
Moreover inplementation for IAsyncEnumerable<> via reflection works fine too.
Reproduced in .NET and .NET Core.
This code needed for IOutputFormatter implementation that get source data as object and have to iterate through it.
described example in dotnetfiddle

Calling new int[0].ToAsyncEnumerable() will return the (internal) type AsyncIListEnumerableAdapter<int>. This type implements among other things IEnumerable<int> so it has the method IEnumerable<int>.GetEnumerator(). However, it implements this method using explicit interface implementation.
An interface method that is explicitly implemented is not available when you call through dynamic (it is private). To access the method you will have to cast the reference to the interface first as explained in this answer to the question Use explicit interface implementations with a dynamic object.

I got the solution. An object have extension method ToAsyncEnumerable which returns IAsyncEnumerable<object>. Thus we can iterate over it:
public async Task Process(object source)
{
using (var enumerator = source.ToAsyncEnumerable().GetEnumerator())
{
while (await enumerator.MoveNext())
{
var item = enumerator.Current;
}
}
}
One can create wrapper that takes IAsyncEnumerable<T> and implements IAsyncEnumerable<object>. Activator creates that wrapper in extension method. Here is the implementation:
public class AsyncEnumerable<T> : IAsyncEnumerable<object>
{
private IAsyncEnumerable<T> _source;
public AsyncEnumerable(IAsyncEnumerable<T> source)
{
_source = source;
}
public IAsyncEnumerator<object> GetEnumerator()
{
return new AsyncEnumerator<T>(_source.GetEnumerator());
}
}
public class AsyncEnumerator<T> : IAsyncEnumerator<object>
{
private IAsyncEnumerator<T> _source;
public AsyncEnumerator(IAsyncEnumerator<T> source)
{
_source = source;
}
public object Current => _source.Current;
public void Dispose()
{
_source.Dispose();
}
public async Task<bool> MoveNext(CancellationToken cancellationToken)
{
return await _source.MoveNext(cancellationToken);
}
}
public static class AsyncEnumerationExtensions
{
public static IAsyncEnumerable<object> ToAsyncEnumerable(this object source)
{
if (source == null)
{
throw new ArgumentNullException(nameof(source));
}
else if (!source.GetType().GetInterfaces().Any(i => i.GetGenericTypeDefinition() == typeof(IAsyncEnumerable<>)))
{
throw new ArgumentException("IAsyncEnumerable<> expected", nameof(source));
}
var dataType = source.GetType()
.GetInterfaces()
.First(i => i.GetGenericTypeDefinition() == typeof(IAsyncEnumerable<>))
.GetGenericArguments()[0];
var collectionType = typeof(AsyncEnumerable<>).MakeGenericType(dataType);
return (IAsyncEnumerable<object>)Activator.CreateInstance(collectionType, source);
}
}

Related

xUnit System.InvalidOperationException : The source 'IQueryable' doesn't implement 'IAsyncEnumerable<ApplicationUser>' [duplicate]

I have a MVC project on ASP.NET Core, my problem is connected with IQueryable and asynchronous. I wrote the following method for search in IQueryable<T>:
private IQueryable<InternalOrderInfo> WhereSearchTokens(IQueryable<InternalOrderInfo> query, SearchToken[] searchTokens)
{
if (searchTokens.Length == 0)
{
return query;
}
var results = new List<InternalOrderInfo>();
foreach (var searchToken in searchTokens)
{
//search logic, intermediate results are being added to `results` using `AddRange()`
}
return results.Count != 0 ? results.Distinct().AsQueryable() : query;
}
I call this in method ExecuteAsync():
public async Task<GetAllInternalOrderInfoResponse> ExecuteAsync(GetAllInternalOrderInfoRequest request)
{
//rest of the code
if (searchTokens != null && searchTokens.Any())
{
allInternalOrderInfo = WhereSearchTokens(allInternalOrderInfo, searchTokens);
}
var orders = await allInternalOrderInfo.Skip(offset).Take(limit).ToArrayAsync();
//rest of the code
}
When I test this I get an InvalidOperationException on line where I call ToArrayAsync()
The source IQueryable doesn't implement IAsyncEnumerable. Only sources that implement IAsyncEnumerable can be used for Entity Framework asynchronous operations.
I had changed ToArrayAsync() to ToListAsync() but nothing have changed. I have searched this problem for a while, but resolved questions are connected mostly with DbContext and entity creating. EntityFramework is not installed for this project and it's better not to do it because of application architecture. Hope someone has any ideas what to do in my situation.
I found I had to do a bit more work to get things to work nicely:
namespace TestDoubles
{
using Microsoft.EntityFrameworkCore.Query.Internal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
public static class AsyncQueryable
{
/// <summary>
/// Returns the input typed as IQueryable that can be queried asynchronously
/// </summary>
/// <typeparam name="TEntity">The item type</typeparam>
/// <param name="source">The input</param>
public static IQueryable<TEntity> AsAsyncQueryable<TEntity>(this IEnumerable<TEntity> source)
=> new AsyncQueryable<TEntity>(source ?? throw new ArgumentNullException(nameof(source)));
}
public class AsyncQueryable<TEntity> : EnumerableQuery<TEntity>, IAsyncEnumerable<TEntity>, IQueryable<TEntity>
{
public AsyncQueryable(IEnumerable<TEntity> enumerable) : base(enumerable) { }
public AsyncQueryable(Expression expression) : base(expression) { }
public IAsyncEnumerator<TEntity> GetEnumerator() => new AsyncEnumerator(this.AsEnumerable().GetEnumerator());
public IAsyncEnumerator<TEntity> GetAsyncEnumerator(CancellationToken cancellationToken = default) => new AsyncEnumerator(this.AsEnumerable().GetEnumerator());
IQueryProvider IQueryable.Provider => new AsyncQueryProvider(this);
class AsyncEnumerator : IAsyncEnumerator<TEntity>
{
private readonly IEnumerator<TEntity> inner;
public AsyncEnumerator(IEnumerator<TEntity> inner) => this.inner = inner;
public void Dispose() => inner.Dispose();
public TEntity Current => inner.Current;
public ValueTask<bool> MoveNextAsync() => new ValueTask<bool>(inner.MoveNext());
#pragma warning disable CS1998 // Nothing to await
public async ValueTask DisposeAsync() => inner.Dispose();
#pragma warning restore CS1998
}
class AsyncQueryProvider : IAsyncQueryProvider
{
private readonly IQueryProvider inner;
internal AsyncQueryProvider(IQueryProvider inner) => this.inner = inner;
public IQueryable CreateQuery(Expression expression) => new AsyncQueryable<TEntity>(expression);
public IQueryable<TElement> CreateQuery<TElement>(Expression expression) => new AsyncQueryable<TElement>(expression);
public object Execute(Expression expression) => inner.Execute(expression);
public TResult Execute<TResult>(Expression expression) => inner.Execute<TResult>(expression);
public IAsyncEnumerable<TResult> ExecuteAsync<TResult>(Expression expression) => new AsyncQueryable<TResult>(expression);
TResult IAsyncQueryProvider.ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken) => Execute<TResult>(expression);
}
}
}
This enables me to write tests like this:
[TestCase("", 3, 5)]
[TestCase("100", 2, 4)]
public async Task GetOrderStatusCounts_ReturnsCorrectNumberOfRecords(string query, int expectedCount, int expectedStatusProductionCount)
{
// omitted CreateOrder helper function
const int productionStatus = 6;
const int firstOtherStatus = 5;
const int otherOtherStatus = 7;
var items = new[]
{
CreateOrder(1, "100000", firstOtherStatus, 1),
CreateOrder(2, "100000", firstOtherStatus, 4),
CreateOrder(3, "100000", productionStatus, 4),
CreateOrder(4, "100001", productionStatus, 4),
CreateOrder(5, "100100", productionStatus, 4),
CreateOrder(6, "200000", otherOtherStatus, 4),
CreateOrder(7, "200001", productionStatus, 4),
CreateOrder(8, "200100", productionStatus, 4)
}.AsAsyncQueryable(); // this is where the magic happens
var mocker = new AutoMocker();
// IRepository implementation is also generic and calls DBCntext
// for easier testing
mocker.GetMock<IRepository<Order>>()
.Setup(m => m.BaseQuery()
.Returns(items);
// the base query is extended in the system under test.
// that's the behavior I'm testing here
var sut = mocker.CreateInstance<OrderService>();
var counts = await sut.GetOrderStatusCountsAsync(4, query);
counts.Should().HaveCount(expectedCount);
counts[OrderStatus.Production].Should().Be(expectedStatusProductionCount);
}
I wrote an ICollection extension AsAsyncQueryable that I use in my tests
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
namespace Whatevaaaaaaaa
{
public static class ICollectionExtensions
{
public static IQueryable<T> AsAsyncQueryable<T>(this ICollection<T> source) =>
new AsyncQueryable<T>(source.AsQueryable());
}
internal class AsyncQueryable<T> : IAsyncEnumerable<T>, IQueryable<T>
{
private IQueryable<T> Source;
public AsyncQueryable(IQueryable<T> source)
{
Source = source;
}
public Type ElementType => typeof(T);
public Expression Expression => Source.Expression;
public IQueryProvider Provider => new AsyncQueryProvider<T>(Source.Provider);
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new AsyncEnumeratorWrapper<T>(Source.GetEnumerator());
}
public IEnumerator<T> GetEnumerator() => Source.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
internal class AsyncQueryProvider<T> : IQueryProvider
{
private readonly IQueryProvider Source;
public AsyncQueryProvider(IQueryProvider source)
{
Source = source;
}
public IQueryable CreateQuery(Expression expression) =>
Source.CreateQuery(expression);
public IQueryable<TElement> CreateQuery<TElement>(Expression expression) =>
new AsyncQueryable<TElement>(Source.CreateQuery<TElement>(expression));
public object Execute(Expression expression) => Execute<T>(expression);
public TResult Execute<TResult>(Expression expression) =>
Source.Execute<TResult>(expression);
}
internal class AsyncEnumeratorWrapper<T> : IAsyncEnumerator<T>
{
private readonly IEnumerator<T> Source;
public AsyncEnumeratorWrapper(IEnumerator<T> source)
{
Source = source;
}
public T Current => Source.Current;
public ValueTask DisposeAsync()
{
return new ValueTask(Task.CompletedTask);
}
public ValueTask<bool> MoveNextAsync()
{
return new ValueTask<bool>(Source.MoveNext());
}
}
}
If you are not going to change your design - you have several options:
1) Change AsQueryable to another method which returns IQueryable which also implements IDbAsyncEnumerable. For example you can extend EnumerableQuery (which is returned by AsQueryable):
public class AsyncEnumerableQuery<T> : EnumerableQuery<T>, IDbAsyncEnumerable<T> {
public AsyncEnumerableQuery(IEnumerable<T> enumerable) : base(enumerable) {
}
public AsyncEnumerableQuery(Expression expression) : base(expression) {
}
public IDbAsyncEnumerator<T> GetAsyncEnumerator() {
return new InMemoryDbAsyncEnumerator<T>(((IEnumerable<T>) this).GetEnumerator());
}
IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator() {
return GetAsyncEnumerator();
}
private class InMemoryDbAsyncEnumerator<T> : IDbAsyncEnumerator<T> {
private readonly IEnumerator<T> _enumerator;
public InMemoryDbAsyncEnumerator(IEnumerator<T> enumerator) {
_enumerator = enumerator;
}
public void Dispose() {
}
public Task<bool> MoveNextAsync(CancellationToken cancellationToken) {
return Task.FromResult(_enumerator.MoveNext());
}
public T Current => _enumerator.Current;
object IDbAsyncEnumerator.Current => Current;
}
}
Then you change
results.Distinct().AsQueryable()
to
new AsyncEnumerableQuery<InternalOrderInfo>(results.Distinct())
And later, ToArrayAsync will not throw exception any more (obviously you can create your own extension method like AsQueryable).
2) Change ToArrayAsync part:
public static class EfExtensions {
public static Task<TSource[]> ToArrayAsyncSafe<TSource>(this IQueryable<TSource> source) {
if (source == null)
throw new ArgumentNullException(nameof(source));
if (!(source is IDbAsyncEnumerable<TSource>))
return Task.FromResult(source.ToArray());
return source.ToArrayAsync();
}
}
And use ToArrayAsyncSafe instead of ToArrayAsync, which will fallback to synchronous enumeration in case IQueryable is not IDbAsyncEnumerable. In your case this only happens when query is really in-memory list and not query, so async execution does not make sense anyway.
For EF Core:
public static class QueryableExtensions
{
public static IQueryable<T> AsAsyncQueryable<T>(this IEnumerable<T> input)
{
return new NotInDbSet<T>( input );
}
}
public class NotInDbSet< T > : IQueryable<T>, IAsyncEnumerable< T >, IEnumerable< T >, IEnumerable
{
private readonly List< T > _innerCollection;
public NotInDbSet( IEnumerable< T > innerCollection )
{
_innerCollection = innerCollection.ToList();
}
public IAsyncEnumerator< T > GetAsyncEnumerator( CancellationToken cancellationToken = new CancellationToken() )
{
return new AsyncEnumerator( GetEnumerator() );
}
public IEnumerator< T > GetEnumerator()
{
return _innerCollection.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public class AsyncEnumerator : IAsyncEnumerator< T >
{
private readonly IEnumerator< T > _enumerator;
public AsyncEnumerator( IEnumerator< T > enumerator )
{
_enumerator = enumerator;
}
public ValueTask DisposeAsync()
{
return new ValueTask();
}
public ValueTask< bool > MoveNextAsync()
{
return new ValueTask< bool >( _enumerator.MoveNext() );
}
public T Current => _enumerator.Current;
}
public Type ElementType => typeof( T );
public Expression Expression => Expression.Empty();
public IQueryProvider Provider => new EnumerableQuery<T>( Expression );
}
For EFCore Bit late to the party but to others looking to resolve this type of problem, one of possible solution is to change code to use Task.FromResult() method in this way:
var result= await allInternalOrderInfo.Skip(offset).Take(limit);
var orders = await Task.FromResult(result.ToArray());
The AsQueryable() will not transform the result list into an Entity Framework IQueryable. And as the error states, the IQueryable that are used with ToArrayAsync() should implement IAsyncEnumerable, which is not what AsQueryable will return.
You can read more about the uses of AsQueryable on enumerables here.
As noted by #Titian Cernicova-Dragomir the exception means that List<InternalOrderInfo> doesn't implement IAsyncEnumerable
But here is a logical/design error. If your method works with IQueryable and returns IQueryable it should work with it as with IQueryable and not as with IEnumarable that assumes that collection is in a memory of app. You really need to read more about the difference between IQueryable and IEnumarable and what you should return from the method. A good point to start is to read answers here and here
So, since you already fetched results from db in WhereSearchTokens method or even before, there is no reason to do asynchronous request to db which is would be done by ToArrayAsync and return IQueryable.
You have two options here:
1) If your collection of InternalOrderInfo is fetched from db into memory before WhereSearchTokens make your all actions in synchronous mode i.e call ToArray instead of ToArrayAsync, and return IEnumerable instead of Taks<IQueryable> from both WhereSearchTokens and ExecuteAsync.
2) If your collection of InternalOrderInfo is fetched inside WhereSearchTokens and you want to do the async request to db you need to call async EF API only somewhere in //search logic, intermediate results are being added to results using AddRange() and again return Taks<IEnumerable> istead of Taks<IQueryable> from WhereSearchTokens
ERROR Message: 
System.InvalidOperationException : The source 'IQueryable' doesn't implement 'IAsyncEnumerable'. Only sources that implement 'IAsyncEnumerable' can be used for Entity Framework asynchronous operations.
For my case the solution: when you are mocking your dbContext and pass data from your mockSet to your context change .Returns to .ReturnsDbSet
Exemple:
var mockContext = new Mock<IWebApiDbContext>(); mockContext.Setup(m => m.User).ReturnsDbSet(mockSet.Object);
Full Code Mock db:
var mockSet = new Mock<DbSet<User>>();
mockSet.As<IDbAsyncEnumerable<User>>()
.Setup(m => m.GetAsyncEnumerator())
.Returns(new TestDbAsyncEnumerator<User>(data.GetEnumerator()));
mockSet.As<IQueryable<User>>()
.Setup(m => m.Provider)
.Returns(new TestDbAsyncQueryProvider<User>(data.Provider));
mockSet.As<IQueryable<User>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<User>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<User>>().Setup(m => m.GetEnumerator()).Returns(() => data.GetEnumerator());
var mockContext = new Mock<IWebApiDbContext>();
mockContext.Setup(m => m.User).ReturnsDbSet(mockSet.Object);
It's better to implement collection with IAsyncEnumerable<T> and IQueryable<T> rather than create your own ToListAsync extensions.
You can't apply your extensions in libraries.
For EF Core 5 and above check this implementation and tests.
Short version:
public sealed class FixedQuery<T> : IAsyncEnumerable<T>, IQueryable<T>
{
public static readonly IQueryable<T> Empty = Create(ArraySegment<T>.Empty);
public static IQueryable<T> Create(params T[] items)
{
return Create((IEnumerable<T>)items);
}
public static IQueryable<T> Create(IEnumerable<T> items)
{
return new FixedQuery<T>(items ?? ArraySegment<T>.Empty).AsQueryable();
}
private readonly IQueryable<T> _items;
private FixedQuery(IEnumerable<T> items)
{
_items = (items ?? throw new ArgumentNullException(nameof(items))).AsQueryable();
}
#pragma warning disable CS1998
public async IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
#pragma warning restore CS1998
{
foreach (var item in _items)
{
yield return item;
}
}
public IEnumerator<T> GetEnumerator()
{
return _items.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public Type ElementType => _items.ElementType;
public Expression Expression => _items.Expression;
public IQueryProvider Provider => _items.Provider;
}

How to convert an existing List/Collection to IAsyncEnumerable [duplicate]

I'm incrementally introducing Ix.NET into a legacy project. I have a number of storage-level APIs that return Task<IEnumerable<T>>, but I want to adapt them to IAsyncEnumerable<T> for consumption in the rest of the system. It seems like there should be a helper method (ala .ToAsyncEnumerable() for IEnumerable) to help with this, but I can't find anything... Do I have to implement my own custom Enumerator? (not hard, but I don't want to re-invent the wheel)
Task<IEnumerable<T>> GetSomeResults<T>()
{
throw new NotImplementedException();
}
async IAsyncEnumerable<T> GetAsyncEnumerable<T>()
{
var results = await GetSomeResults<T>();
foreach(var item in results)
{
yield return item;
}
}
If you're talking about web APIs, Task<IEnumerable<T>> is an asynchronous way of producing a IEnumerable<T>.
Regardless of that IEnumerable<T> being produced synchronously or asynchronously, the whole list will be sent as an HTTP response.
The way you could leverage IAsyncEnumerable<T> on the client is if that client is invoking some kind of streaming or making multiple requests to a server for a unique list of results (paging).
I was looking for the exact same thing, and due to the replies here I assume that there is indeed no method like AsAsyncEnumerable(). So here's what I ended up doing, maybe it helps soneone else:
public static class AsyncEnumerableExtensions {
public struct AsyncEnumerable<T> : IAsyncEnumerable<T> {
private readonly IEnumerable<T> enumerable;
public AsyncEnumerable(IEnumerable<T> enumerable) {
this.enumerable = enumerable;
}
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken()) {
return new AsyncEnumerator<T>(enumerable?.GetEnumerator());
}
}
public struct AsyncEnumerator<T> : IAsyncEnumerator<T> {
private readonly IEnumerator<T> enumerator;
public AsyncEnumerator(IEnumerator<T> enumerator) {
this.enumerator = enumerator;
}
public ValueTask DisposeAsync() {
enumerator?.Dispose();
return default;
}
public ValueTask<bool> MoveNextAsync() {
return new ValueTask<bool>(enumerator == null ? false : enumerator.MoveNext());
}
public T Current => enumerator.Current;
}
public static AsyncEnumerable<T> AsAsyncEnumerable<T>(this IEnumerable<T> that) {
return new AsyncEnumerable<T>(that);
}
public static AsyncEnumerator<T> AsAsyncEnumerator<T>(this IEnumerator<T> that) {
return new AsyncEnumerator<T>(that);
}
}
As commented by Theodor Zoulias,
System.Linq.Async is a NuGet package from .NET Foundation, which supports ToAsyncEnumerable().
Example usage:
var tasks = new Task[0]; // get your IEnumerable<Task>s
tasks.ToAsyncEnumerable();
public static async IAsyncEnumerable<T> ToAsyncEnumerable<T>(this IEnumerable<T> enumerable)
{
using IEnumerator<T> enumerator = enumerable.GetEnumerator();
while (await Task.Run(enumerator.MoveNext).ConfigureAwait(false))
{
yield return enumerator.Current;
}
}

How can I "adapt" a Task<IEnumerable<T>> to IAsyncEnumerable<T>?

I'm incrementally introducing Ix.NET into a legacy project. I have a number of storage-level APIs that return Task<IEnumerable<T>>, but I want to adapt them to IAsyncEnumerable<T> for consumption in the rest of the system. It seems like there should be a helper method (ala .ToAsyncEnumerable() for IEnumerable) to help with this, but I can't find anything... Do I have to implement my own custom Enumerator? (not hard, but I don't want to re-invent the wheel)
Task<IEnumerable<T>> GetSomeResults<T>()
{
throw new NotImplementedException();
}
async IAsyncEnumerable<T> GetAsyncEnumerable<T>()
{
var results = await GetSomeResults<T>();
foreach(var item in results)
{
yield return item;
}
}
If you're talking about web APIs, Task<IEnumerable<T>> is an asynchronous way of producing a IEnumerable<T>.
Regardless of that IEnumerable<T> being produced synchronously or asynchronously, the whole list will be sent as an HTTP response.
The way you could leverage IAsyncEnumerable<T> on the client is if that client is invoking some kind of streaming or making multiple requests to a server for a unique list of results (paging).
I was looking for the exact same thing, and due to the replies here I assume that there is indeed no method like AsAsyncEnumerable(). So here's what I ended up doing, maybe it helps soneone else:
public static class AsyncEnumerableExtensions {
public struct AsyncEnumerable<T> : IAsyncEnumerable<T> {
private readonly IEnumerable<T> enumerable;
public AsyncEnumerable(IEnumerable<T> enumerable) {
this.enumerable = enumerable;
}
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = new CancellationToken()) {
return new AsyncEnumerator<T>(enumerable?.GetEnumerator());
}
}
public struct AsyncEnumerator<T> : IAsyncEnumerator<T> {
private readonly IEnumerator<T> enumerator;
public AsyncEnumerator(IEnumerator<T> enumerator) {
this.enumerator = enumerator;
}
public ValueTask DisposeAsync() {
enumerator?.Dispose();
return default;
}
public ValueTask<bool> MoveNextAsync() {
return new ValueTask<bool>(enumerator == null ? false : enumerator.MoveNext());
}
public T Current => enumerator.Current;
}
public static AsyncEnumerable<T> AsAsyncEnumerable<T>(this IEnumerable<T> that) {
return new AsyncEnumerable<T>(that);
}
public static AsyncEnumerator<T> AsAsyncEnumerator<T>(this IEnumerator<T> that) {
return new AsyncEnumerator<T>(that);
}
}
As commented by Theodor Zoulias,
System.Linq.Async is a NuGet package from .NET Foundation, which supports ToAsyncEnumerable().
Example usage:
var tasks = new Task[0]; // get your IEnumerable<Task>s
tasks.ToAsyncEnumerable();
public static async IAsyncEnumerable<T> ToAsyncEnumerable<T>(this IEnumerable<T> enumerable)
{
using IEnumerator<T> enumerator = enumerable.GetEnumerator();
while (await Task.Run(enumerator.MoveNext).ConfigureAwait(false))
{
yield return enumerator.Current;
}
}

Moq - setup Where extension?

How to set up where linq extension on object? DbSet in my case. Here is my code:
this.workflowStateSet
.Setup(m => m.Where(It.IsAny<Expression<Func<Model.WorkflowState, int, bool>>>()))
.Returns(new List<Model.WorkflowState>().AsQueryable());
However, it gives me exception not very familiar exception:
System.NotSupportedException: Expression references a method that
does not belong to the mocked object: m => m.Where<WorkflowState>
I will be grateful for any hint.
This extension method will help mock the DbSet
public static class MockDbSetExtensions {
public static Mock<DbSet<T>> AsDbSetMock<T>(this IEnumerable<T> list) where T : class {
IQueryable<T> queryableList = list.AsQueryable();
Mock<DbSet<T>> dbSetMock = new Mock<DbSet<T>>();
dbSetMock.As<IQueryable<T>>().Setup(x => x.Provider).Returns(queryableList.Provider);
dbSetMock.As<IQueryable<T>>().Setup(x => x.Expression).Returns(queryableList.Expression);
dbSetMock.As<IQueryable<T>>().Setup(x => x.ElementType).Returns(queryableList.ElementType);
dbSetMock.As<IQueryable<T>>().Setup(x => x.GetEnumerator()).Returns(() => queryableList.GetEnumerator());
return dbSetMock;
}
}
And you can use it like this.
//Arrange
var data = new List<Model.WorkflowState>();
//you would populate your list as needed.
//convert it to a mock DbSet that uses the list as its datasource
var workflowStateSet = data.AsDbSetMock();
var dbSet = workflowStateSet.Object;
//Act
var items = dbSet.Where("Your expression here");
//Assert
//....
Use the repository pattern to add a layer of abstraction to the data retrieval. This abstraction can then be mocked.
If, for example, you were trying to retrieve all of the workflows with a stateId equal to 1, then rather than calling something like this
var result = DbSet.WorkflowState.Where(w => w.stateId == 1);
move this code into another class and then create an interface of the method signature.
public interface IWorkflowStateSetRepository{
IQueryable<Model.WorkflowState> GetAllWorkflows(int state);
}
implementation
public class WorkflowStateSetRepository : IWorkflowStateSetRepository{
public IQueryable<Model.WorkflowState> GetAllWorkflows(int state){
return DbSet.WorkflowState .Where(w => w.stateId == state);
}
}
In the calling code get an instance of IWorkflowStateSetRepository (probably from your IoC container) and call the GetAllWorkflows() method instead. This will give you the same results as before but you can now mock the interface in your tests and setup calls to that methods.
this.MockedIWorkflowStateSetRepository.Setup(m => m.GetAllWorkflows(It.IsAny<int>()))
.Returns(new List<Model.WorkflowState>().AsQueryable());
This code is more maintainable and (with appropriately named variables and methods) also conveys the intent a lot better.
The repository pattern is discussed in greater detail here;
http://www.asp.net/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application
Are you trying to Mock up a real DbSet instance ? Cause this won't work, as the error message try to explain you. To mock a type, it must either be an interface or have virtual members (abstract members are also virtual).
You can try to mock up IDbSet or to create a custom DbSet class, for instance something like the following class
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
public class DbSetMock<T> : DbSet<T>, IDbSet<T>
where T : class
{
private readonly ICollection<T> _contentCollection;
public DbSetMock(IList<T> contentCollection = null)
{
_contentCollection = new Collection<T>(contentCollection ?? new List<T>());
AddedEntities = new List<T>();
RemovedEntities = new List<T>();
AttachedEntities = new List<T>();
}
public void OverrideContentCollection(IEnumerable<T> newData)
{
_contentCollection.Clear();
_contentCollection.AddRange(newData);
}
public IList<T> AddedEntities { get; private set; }
public IList<T> AttachedEntities { get; private set; }
public override ObservableCollection<T> Local
{
get
{
throw new NotImplementedException();
}
}
public IList<T> RemovedEntities { get; private set; }
public Type ElementType
{
get
{
return typeof(T);
}
}
public Expression Expression
{
get
{
return _contentCollection.AsQueryable().Expression;
}
}
public IQueryProvider Provider
{
get
{
return _contentCollection.AsQueryable().Provider;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return _contentCollection.GetEnumerator();
}
public override T Add(T entity)
{
AddedEntities.Add(entity);
_contentCollection.Add(entity);
return entity;
}
public override T Attach(T entity)
{
AttachedEntities.Add(entity);
var matchingEntity = _contentCollection.SingleOrDefault(x => x.Id == entity.Id);
if (matchingEntity != null)
{
_contentCollection.Remove(matchingEntity);
}
_contentCollection.Add(entity);
return entity;
}
public override TDerivedEntity Create<TDerivedEntity>()
{
throw new NotImplementedException();
}
public override T Create()
{
throw new NotImplementedException();
}
public override T Find(params object[] keyValues)
{
throw new NotImplementedException();
}
public override T Remove(T entity)
{
RemovedEntities.Add(entity);
_contentCollection.Remove(entity);
return entity;
}
}
You can use constructor parameter to setup content that will be retrieved by the db set.
Hope this helps.

How to create IEnumerable<T> on which multiple enumerations are not possible?

When I enumerate over an IEnumerable twice Resharper complains about Possible multiple enumerations of IEnumerable. I know, in some case of DB-queries when you enumerate twice you get an exception.
I want to reproduce that behavior in tests. So, I basically want the following function to throw (because of multiple enumerations):
private void MultipleEnumerations(IEnumerable<string> enumerable)
{
MessageBox.Show(enumerable.Count().ToString());
MessageBox.Show(enumerable.Count().ToString());
}
What should I pass to it? All the Lists, Collections etc. are ok with multiple enumerations.
Even this kind of IEnumerable doesn't give an exception:
private IEnumerable<string> GetIEnumerable()
{
yield return "a";
yield return "b";
}
Thanks.
You probably just want a custom class:
public class OneShotEnumerable<T> : IEnumerable<T>
{
private readonly IEnumerable<T> _source;
private bool _shouldThrow = false;
public OneShotEnumerable(IEnumerable<T> source)
{
this._source = source;
}
public IEnumerator<T> GetEnumerator()
{
if (_shouldThrow) throw new InvalidOperationException();
_shouldThrow = true;
return _source.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Create your own class that implements IEnumerable<T> and throw an exception if GetEnumerator() is called twice (use a boolean instance field).
Alternatively, create an iterator that uses a flag field to ensure that it cannot be called twice (enumerating an iterator twice will execute the entire method twice).
The custom class, which I've copied from John Gietzen's answer (with a couple of corrections), could usefully be combined with an extension method to create a really simple way to do this.
public class OneShotEnumerable<T> : IEnumerable<T>
{
private readonly IEnumerable<T> source;
private bool shouldThrow = false;
public OneShotEnumerable(IEnumerable<T> source)
{
this.source = source;
}
public IEnumerator<T> GetEnumerator()
{
if (shouldThrow)
throw new InvalidOperationException("This enumerable has already been enumerated.");
shouldThrow = true;
return this.source.GetEnumerator();
}
}
public static clas OneShotEnumerableExtension
{
public static IEnumerable<T> SingleUse<T>(this IEnumerable<T> source)
{
#if (DEBUG)
return new OneShotEnumerableExtension(source);
#else
return source;
#endif
}
}
Then you can pass something to your previous method by simply doing
MultipleEnumerations(MyEnumerable.SingleUse());

Categories

Resources