Kasper P
Kasper P

Reputation: 820

Asynchronous method has no availble extension methods, but resulting variable does have

I'm createing some methods in a standard repository class using MongoDB with c# and async methods and I've stumbled upon some strange behaviour.

In the end it's probably not strange at all, rather the problem lies in my own inexperience with async programming.

Consider this code:

public async Task<T> GetItem<T>(ObjectId id) where T : BaseItemEntity
        {
            var col = GetTypedCollection<T>();

            var model = await col.FindAsync(x => x.Id == id);

            return await model.FirstOrDefaultAsync();
        }

Now that is totally fine, no compilation errors but I'm actually not sure its's correct calling await 2 times.

Now consider this code:

public async Task<T> GetItem<T>(ObjectId id) where T : BaseItemEntity
        {
            var col = GetTypedCollection<T>();

            var model = await col.FindAsync(x => x.Id == id).FirstOrDefaultAsync();

            return model;
        }

Thats illegal according to the compiler. It's complaining about FirstOrDefaultAsync() not being an availble method to call. I would have to call .Result first to get access to .FirstOrDefaultAsync().

What is going on here?

Upvotes: 2

Views: 377

Answers (2)

Clint
Clint

Reputation: 6220

var model = await col.FindAsync(x => x.Id == id).FirstOrDefaultAsync();

Should be:

var model = await (await col.FindAsync(x => x.Id == id)).FirstOrDefaultAsync();

This is because FindAsync returns a Task object, which FirstOrDefaultAsync doesn't work for. Awaiting the operation yields the actual result.

This is one of the most annoying things with async/await IMO, as it requires parentheses or variables to hold the awaited result for further processing.

Upvotes: 3

andrisbandris
andrisbandris

Reputation: 131

I think it actually should be

var model = await (await col.FindAsync(x => x.Id == id)).FirstOrDefaultAsync();

both Async methods return a Task object, and Tasks don't have FirstOrDefault() method( this is why await in () is required). The other one is needed because this way model is your object and not a Task.

Upvotes: 1

Related Questions