mrtaikandi
mrtaikandi

Reputation: 6948

EF6 ToListAsync freezes Winforms

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

Answers (2)

Paulo Morgado
Paulo Morgado

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

Tien Dinh
Tien Dinh

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

Related Questions