Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF UI blocking while awaiting DbContext

I'm experimenting with async await and I'm encountering UI blocking that shouldn't be happening.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        LoadButton.Click += LoadButton_OnClick;
    }

    private async void LoadButton_OnClick(object sender, RoutedEventArgs e)
    {
        LoadButton.IsEnabled = false;

        // await Task.Delay(2000);

        using(TestContext ctx = new TestContext())
        {
            IList<User> users = await ctx.Users.ToListAsync();
        }

        LoadButton.IsEnabled = true;
    }
}

If I comment the DbContext bit and uncomment Task.Delay, it behaves as expected - non blocking the UI.

Based on my understanding, the ToListAsync() method is still invoked from the UI thread but shouldn't block it. Even if the method is CPU-bound (probably isn't) it would cause lag, not a complete block.

My questions:

Do I understand this correctly?

Why is my UI blocking while awaiting on ToListAsync() ?


EDIT

I tried doing a database call before calling this method to warm everything and ensure it doesn't block on establishing the first connection. Also I tried adding a couple of thousand entries to the DbSet and awaiting on SaveChangesAsync and the same thing happens - the UI freezes completely for several seconds.


EDIT 2

I tried another example with the same code and it seems to be working. The difference is that in first example I'm using Code First and SQL CE and in the working example Database First and SQL Server.

like image 727
loodakrawa Avatar asked Sep 26 '22 15:09

loodakrawa


1 Answers

The connection objects used in SQL Server CE are not threadsafe (the naturally async APIs are not implemented). I believe you are encountering this issue with SQL CE as it is executing on the thread which created the DbContext and not returning control back to the UI thread when awaited. Try instantiating the DbContext within a Task and awaiting the result.

LoadButton.IsEnabled = false;

var users = await Task.Run(() => 
{
    using(TestContext ctx = new TestContext())
    {
        return ctx.Users.ToList();
    }
});

LoadButton.IsEnabled = true;
like image 124
Alex Wiese Avatar answered Sep 29 '22 06:09

Alex Wiese