Bjorn De Rijcke
Bjorn De Rijcke

Reputation: 683

MongoDB endless Find ToListAsync

I'm attempting to retrieve data from a MongoDB collection, however something strange is happening. If I show a MessageBox the data fetch works, if I don't it doesn't.

static class MongoDBController {
    static MongoClient client = new MongoClient("mongodb://localhost");

    public static async Task<List<Course>> GetCourses(string dbName = "school") {            
        // Get our course collection
        var db = client.GetDatabase(dbName);
        var collection = db.GetCollection<Course>("courses");

        // Create an empty filter
        var filter = new BsonDocument();

        // Use the empty filter to get all courses from the database
        return await collection.Find(filter).ToListAsync();
    }
}

The code above gets the content out of the database, the code below - found in my Form1.cs - places it inside a ListBox.

private void FillCourseList() {
    Task<List<Course>> courseTask = MongoDBController.GetCourses();

    MessageBox.Show("Fetching worked (yay!)");

    // get the result
    List<Course> result = courseTask.Result;

    // Show every course found in the resultset
    foreach (Course s in result) {
        listBox_overview_vakken.Items.Add(s);
    }
}

Now if I remove the Fetching worked (yay!) pop-up my listBox never gets filled.

What am I doing wrong?

Upvotes: 3

Views: 3055

Answers (1)

Bjorn De Rijcke
Bjorn De Rijcke

Reputation: 683

The solution to the issue, as Alex kindly pointed out, is making the FillCourseList asynchronous aswell. This allows the program to continue running while the data is fetched from the database. The blocking call I had before apparently was the cause of the issue. This does add the need for thread-safe calls to the Windows Form though.

    private delegate void SetListCallback(List<Course> result);

    private async Task GetCourseList() {
        Task<List<Course>> courseTask = MongoDBController.GetCourses();
        List<Course> result = await courseTask.ConfigureAwait(false);

        // When finished, fill the listbox
        FillCourseList(result);
    }

    private void FillCourseList(List<Course> result) {
        // If the calling thread's ID doesn't match the creating thread's ID
        // Invoke this method on the correct thread via the delegate
        if (this.listBox_overview_vakken.InvokeRequired) {
            SetListCallback d = new SetListCallback(FillCourseList);
            this.Invoke(d, result);
        } else {
            foreach (Course s in result) {
                listBox_overview_vakken.Items.Add(s);
            }
        }
    }

Upvotes: 3

Related Questions