问题
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 ?
回答1:
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
回答2:
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
targetFrameworkto 4.5, or setUseTaskFriendlySynchronizationContextto true. - (WebForms only) Set
Page.Asyncto true. - Consider using
RegisterAsyncTaskinstead ofawait. I usually preferawaitbecause different methods have more separation of concerns, but the ASP.NET team prefersRegisterAsyncTaskbecause there is a single "synchronize" point afterPreRenderwhere 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.TimedOutcancellation token. - (WebForms/
RegisterAsyncTaskonly) You can add an asynchronous timeout by settingPage.AsyncTimeoutand having yourasyncmethod take aCancellationToken.
- Use the
回答3:
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
来源:https://stackoverflow.com/questions/17587157/entityframework-6-and-async-waitingforactivation