Reputation: 6948
I have a simple Winforms application with a button on it. Using EF 6.1.1 code first, if I use .ToListAsync on a query it will freeze the form until the result came back from the SQL Server.
private async void button1_Click(object sender, EventArgs e)
{
using( var context = new MyEFContext() )
{
var result = await context.MyTable.ToListAsync();
MessageBox.Show(result.Count);
}
}
If I put the .ToListAsync() call in a different synchronization context say by adding await Task.Delay(1).ConfigureAwaiter(false)
before it, it works as it should be.
Does anybody know what I'm missing here? Why is it like this?
Upvotes: 4
Views: 1765
Reputation: 14846
Basically, all async
code is synchronous until the first await
.
What might be happening is the setup (opening connection and such) taking too many time.
You should always push as much as you can outside of the UI thread. Something like this:
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;
private async void button1_Click(object sender, EventArgs e)
{
this.button1.Enabled = false;
var result = await GetMyTableAsync();
MessageBox.Show(result.Count);
this.button1.Enabled = true;
}
private async Task<IList<MyTableEntity>> GetMyTableAsync()
{
using( var context = new MyEFContext() )
{
return await context.MyTable.ToListAsync()
.ConfigureAwait(false);
}
}
Upvotes: 2
Reputation: 1038
Querying a database is an IO bound operation, so by design, it run under the same synchronisation context as the calling code.
The typical intent usage is
var task = context.Table.ToListAsync();
// do something else here
var result = await task;
However, if you have nothing else to do then it is better to spawn a thread
var result = await Task.Run<List<Table>>(() => context.Table.ToListAsync());
which mean that your task is now both cpu and io bound
Upvotes: -1