I've downloaded EF6 ( in order to use async
)
So I wrote this simple method :
public async Task<List<int>> MyasyncMethod()
{
var locations = await MyDumpEntities.AgeGroups.Select(f=>f.endYear).ToListAsync();
return locations;
}
...Later...
DumpEntities1 MyDumpEntities = new DumpEntities1();
var data = MyDumpEntities.AgeGroups.ToListAsync();
MyasyncMethod().ContinueWith(s => { Response.Write("f"); });
MyDumpEntities.Dispose();
But I don't see anything on the screen and when I inspect data
I see this :
p.s. this is the ToListAsync
signature
What am I missing ?
Basing it of off the comments and the line that you have problem with:
var data = MyDumpEntities.AgeGroups.ToListAsync();
What will data
type be? Task<List<AgeGroup>>
. That's right, not List<AgeGroup>
.
So, you either have to mark the Page_Load
as async (if possible):
public async void Page_Load(object sender, EventArgs e)
{
using(var MyDumpEntities = new DumpEntities1())
{
var data = await MyDumpEntities.AgeGroups.ToListAsync();
}
}
Or wait for the execution somehow (continuation, blocking wait).
Another thing (someone else might want to correct that if I'm wrong), but since you're using continuation for the second call, I would be very careful of disposing the context outside of continuation. It might turn out that you dispose the context preemptively. In this particular case, you're not using the context in the continuation, but it looks suspicious...
So I'd either
MyasyncMethod().ContinueWith(s => { Response.Write("f"); MyDumpEntities.Dispose();});
Or just use async
there too
var result = await MyasyncMethod();
Response.Write("f");
MyDumpEntities.Dispose();
and add Async="True"
to the page directive
Others have pointed out that the correct solution is to use await
, but I don't see a good explanation of why.
There are two reasons why the original code is wrong. First, you're using ContinueWith
without capturing the context in an ASP.NET application, so the continuation (the Response.Write
call) does not have a request context and therefore has no response to write to.
await
takes care of this for you by capturing the context before the await
and using that to resume the rest of the method; in this case, it will capture an AspNetSynchronizationContext
representing the current request/response.
The other reason is that asynchronous code will run concurrently. So, MyasyncMethod
will begin executing, reach its await
, and return an uncompleted task to Page_Load
. Page_Load
then attaches a continuation to that task and continues executing, disposing the context. So the context may be disposed while the ToListAsync
request is still running.
await
also fixes this for you because it will "pause" the Page_Load
method until MyasyncMethod
is complete.
As a final note, you should also consider these points when using async
in ASP.NET:
- You must target .NET 4.5. Do not use
Microsoft.Bcl.Async
.
- You must set
targetFramework
to 4.5, or set UseTaskFriendlySynchronizationContext
to true.
- (WebForms only) Set
Page.Async
to true.
- Consider using
RegisterAsyncTask
instead of await
. I usually prefer await
because different methods have more separation of concerns, but the ASP.NET team prefers RegisterAsyncTask
because there is a single "synchronize" point after PreRender
where the runtime waits for all the operations to complete. See this article for how to use RegisterAsyncTask
.
- Build in your own request timeouts. Asynchronous ASP.NET requests do not automatically use the normal timeouts that are built-in to synchronous ASP.NET requests. There are two options:
- Use the
HttpRequest.TimedOut
cancellation token.
- (WebForms/
RegisterAsyncTask
only) You can add an asynchronous timeout by setting Page.AsyncTimeout
and having your async
method take a CancellationToken
.
ToListAsync
returns a Task
. Mark Page_Load
as async, then you can use await in it.
Rough rule: If something returns a Task (contains "Async" in method name), you have to await it.
Also, when using async/await you don't have to use ContinueWith
. Just await your own method and place the Write
call in the next line.
DumpEntities1 MyDumpEntities = new DumpEntities1();
var data = await MyDumpEntities.AgeGroups.ToListAsync();
var dataFromMyMethod = await MyasyncMethod()
Response.Write("f");
MyDumpEntities.Dispose();
and add Async="True"
to the page directive