title: .Net Core 2.2 web api with Entity Framework and Linq not able to do async tasks?
body: <p>I have a .NET Core 2.2 web api in which I wanted to have the controllers return results asynchronously. In going async all the way, calls in the browser to test the get by id and get all worked. </p>
  
  <p>The controller unit tests worked as well, but when I went to create my service level unit tests which involve mocking the context, I came across the error</p>
  
  <pre><code>System.AggregateException : One or more errors occurred. (The provider for the source IQueryable doesn't implement IAsyncQueryProvider. Only providers that implement IAsyncQueryProvider can be used for Entity Framework asynchronous operations.)
  </code></pre>
  
  <p>As I dug into this error, I came across blogs and stackoverflow articles that said the only way to do this is to wrap the code inside a Task.FromResult.</p>
  
  <p>One such article is: 
  <a href="https://expertcodeblog.wordpress.com/2018/02/19/net-core-2-0-resolve-error-the-source-iqueryable-doesnt-implement-iasyncenumerable/" rel="nofollow noreferrer">https://expertcodeblog.wordpress.com/2018/02/19/net-core-2-0-resolve-error-the-source-iqueryable-doesnt-implement-iasyncenumerable/</a></p>
  
  <p>This implies that EF is not actually able to do actual async work or that I do not understand something fundamental (the 2nd option is probably most likely - but I want to confirm).</p>
  
  <p>Code-wise, my service is as follows (just the get methods to narrow this)</p>
  
  <pre><code>namespace MoneyManagerAPI.Services
  {
      public class CheckingService : ICheckingService
      {
          readonly CheckbookContext context;
  
          public CheckingService(CheckbookContext context)
          {
              this.context = context;
          }
  
          public async Task&lt;Checking[]&gt; GetAllRecordsAsync()
          {
              return await Task.FromResult(context.Checking.OrderByDescending(m =&gt; m.Id).ToArray());
          }
  
          public async Task&lt;Checking&gt; GetByIdAsync(int id)
          {
              return await Task.FromResult(context.Checking.FirstOrDefault(c =&gt; c.Id == id));
              //return await context.Checking.FirstOrDefaultAsync(c =&gt; c.Id == id);
          }
      }
  }
  </code></pre>
  
  <p>In the GetByIdAsync method, if the commented line of code is uncommented and the other return statement is commented instead the code still compiles but throws the exception method when tested.</p>
  
  <p>My test class has the following code:</p>
  
  <pre><code>namespace Unit.Services
  {
      [TestFixture]
      public class CheckingServiceTests : CheckingHelper
      {
          [Test]
          public void GetAllRecordsAsync_ShouldReturnAllRecords()
          {
              // arrange
              var context = this.CreateCheckingDbContext();
              var service = new CheckingService(context.Object);
              var expectedResults = Task.FromResult(CheckingHelper.GetFakeCheckingData().ToArray());
  
              // act
              var task = service.GetAllRecordsAsync();
  
              task.Wait();
              var result = task.Result;
  
              // assert
              expectedResults.Result.Should().BeEquivalentTo(result);
          }
  
          [Test]
          public void GetByIdAsync_ShouldReturnRequestedRecord()
          {
              // arrange
              var id = 2;
              var context = this.CreateCheckingDbContext();
              var service = new CheckingService(context.Object);
              var expectedResult = CheckingHelper.GetFakeCheckingData().ToArray()[1];
  
              // act
              var task = service.GetByIdAsync(id);
  
              task.Wait();
              var result = task.Result;
  
              // assert
              expectedResult.Should().BeEquivalentTo(result);
          }
  
          Mock&lt;CheckbookContext&gt; CreateCheckingDbContext()
          {
              var checkingData = GetFakeCheckingData().AsQueryable();
              var dbSet = new Mock&lt;DbSet&lt;Checking&gt;&gt;();
              dbSet.As&lt;IQueryable&lt;Checking&gt;&gt;().Setup(c =&gt; c.Provider).Returns(checkingData.Provider);
              dbSet.As&lt;IQueryable&lt;Checking&gt;&gt;().Setup(c =&gt; c.Expression).Returns(checkingData.Expression);
              dbSet.As&lt;IQueryable&lt;Checking&gt;&gt;().Setup(c =&gt; c.ElementType).Returns(checkingData.ElementType);
              dbSet.As&lt;IQueryable&lt;Checking&gt;&gt;().Setup(c =&gt; c.GetEnumerator()).Returns(checkingData.GetEnumerator());
  
              var context = new Mock&lt;CheckbookContext&gt;();
              context.Setup(c =&gt; c.Checking).Returns(dbSet.Object);
  
              return context;
          }
      }
  }
  </code></pre>
  
  <p>Finally, the GetFakeCheckingData is as follows:</p>
  
  <pre><code>namespace Unit.Shared
  {
      public class CheckingHelper
      {
          public static IEnumerable&lt;Checking&gt; GetFakeCheckingData()
          {
              return new Checking[3]
              {
                  new Checking
                  {
                      AccountBalance = 100,
                      Comment = "Deposit",
                      Confirmation = "Test Rec 1",
                      Credit = true,
                      Id = 1,
                      TransactionAmount = 100,
                      TransactionDate = new DateTime(2019, 8, 1, 10, 10, 10)
                  },
                  new Checking
                  {
                      AccountBalance = 90,
                      Comment = "Withdrawal",
                      Confirmation = "Test Rec 2",
                      Credit = false,
                      Id = 2,
                      TransactionAmount = -10,
                      TransactionDate = new DateTime(2019, 8, 10, 10, 10, 10)
                  },
                  new Checking
                  {
                      AccountBalance = 50,
                      Comment = "Deposit",
                      Confirmation = "Test Rec 3",
                      Credit = true,
                      Id = 3,
                      TransactionAmount = 50,
                      TransactionDate = new System.DateTime(2019, 9, 21, 10, 10, 10)
                  }
              };
          }
      }
  }
  </code></pre>