16

I am using asp.net MVC-5 with EF-6, and I am not sure if using await + ToListAsync is valid. For example, I have the following repository method which returns an IQueryable :-

public IQueryable<TSet> getAllScanEmailTo()
{
    return t.TSets.Where(a=>a.Name.StartsWith("ScanEmail"));    
}

And I am calling it as follow:-

var emailsTo = await repository.getAllScanEmailTo().ToListAsync();

In the beginning, I thought I will get an error because I am using "await" a method which is not defined as a task, but the above worked well, so can anyone advice on this, please ?

Blue Clouds
  • 7,295
  • 4
  • 71
  • 112
John John
  • 1
  • 72
  • 238
  • 501

3 Answers3

26

At the beginning I thought I will get an error because I am using "await" a method which is not defined as a task, but the above worked well

Actually, you are awaiting a method which returns a Task<T>, where T is a List<TSet>. If you look at the extension method QueryableExtensions.ToListAsync, you'll see that it returns a Task<List<TSource>>. You are asynchronously waiting on this method to query the database, create the list and return it back to the caller. When you await on such a method, the method won't return until the operation has completed. async-await makes your code feel synchronous, while execution is actually asynchronous.

openshac
  • 4,966
  • 5
  • 46
  • 77
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • 1
    Good & complete explanation. – Hossein Narimani Rad Sep 24 '15 at 11:47
  • @Yuval of i am already aware of this ,, but usually i use await over a Task,, and all the method chain inside my code will be Task + await.. but since i can not wrap the IQueryable with a Task so i did it in this way ,, i am using IQueryable --> await .tolistasync() ... so will this code works as-if the IQueryable is wrapped inside a Task?. so in my case the iis thread will be released till the tolistasync() complete execution , as normal await works ? – John John Sep 24 '15 at 12:04
  • @johnG Yes. The thread will be released while the query executes, and returned once the it finishes. – Yuval Itzchakov Sep 24 '15 at 12:05
  • @YuvalItzchakov so even if i am not wrapping the IQurable inside a Task (becuase i can not do so) , this will still behave as-if the IQurable is wrapped inside a task , so the normal await + Task will still apply here? – John John Sep 24 '15 at 12:09
  • @johnG Yup, it will. No need to wrap this in a `Task` yourself, that will be of no-use. – Yuval Itzchakov Sep 24 '15 at 12:09
  • but if i am returning an entity such as "public Employee getEmployee()" instead of IQueryable then wrapping the method inside a task is a must ? is this correct ? but for IQueryable i do not need to do so , since IQueryable is just a way to build the query that will be used later,, is this correct ? – John John Sep 24 '15 at 12:13
  • 1
    @johnG If your method executes synchronously, and returns an `Employee`, then you can't run it asynchronously, because the API itself is synchronous. – Yuval Itzchakov Sep 24 '15 at 12:15
  • 1
    @YuvalItzchakov but if i use SingleOrDefualtAsync then i can get single employee async ? is this correct ? – John John Sep 24 '15 at 12:51
19

Actually there is no problem because you are awating the ToListAsync() not the getAllScanEmailTo().

EDIT: To see how async-await pattern is working you can see this link. Here is a usefull image from there

enter image description here

Hossein Narimani Rad
  • 31,361
  • 18
  • 86
  • 116
  • so is my approach valid ? or doing so will suspend execution until the ToListAsync() method of the IQueryable completes. – John John Sep 24 '15 at 11:36
  • yes i know this execution path very well, but my original question was how will await + Iqurable works together. since i can not wrap an IQueryable inside a task.. so i am using await + ToListAsync() but over a non-task method, so will this have any side-effect,, or my code will work as-if I have wrapped the IQueryable inside a Task ?? did u get my point ? – John John Sep 24 '15 at 12:07
4

You are not "awaiting a method". You are awaiting a Task, which is an awaitable.

You call getAllScanEmailTo that returns an IQueryable<TSet> on which you then call ToListAsync which returns the Task<List<TSet>> you are awaiting.

i3arnon
  • 113,022
  • 33
  • 324
  • 344
  • so using IQuerable with await as i am doing is valid ? or doing so will suspend execution until the ToListAsync() method of the IQueryable completes. – John John Sep 24 '15 at 11:36
  • @johnG yes. You are awaiting the `Task`, not the `IQueryable`. And yes, you will wait for `ToListAsync` to complete. – i3arnon Sep 24 '15 at 11:37
  • but is doing so will suspend execution until the ToListAsync() method of the IQueryable completes ?? – John John Sep 24 '15 at 11:38
  • @johnG yes. await will asynchronously wait for the operation to complete. – i3arnon Sep 24 '15 at 11:39
  • yes i know ,, but here i am asking if the IIS thread will say occupied till the method is completed ? or it will be released during the method execution ? – John John Sep 24 '15 at 12:00
  • 1
    @johnG no. When you await an asynchronous operation the thread is released. – i3arnon Sep 24 '15 at 12:13
  • so can i say for this scenario i can assume that the IQuerable is wrapped inside a Task ? so in this case nothing really matter if the iQuerable is not being wrapped inside a Task , this was my original question? – John John Sep 24 '15 at 12:53