简体   繁体   中英

blocking main thread on async/await

I am trying to make my base repository class asynchronous and I am running into some trouble. I am using Dapper ORM in my C# application.

Base method

protected async Task<List<T>> Read<T>(CommandDefinition cmd) {
    using(SqlConnection myCon = new SqlConnection(Config.DBConnection)) {
        await myCon.OpenAsync();

        IEnumerable<T> results = await myCon.QueryAsync<T>(cmd);

        List<T> retVal = results.ToList();

        myCon.Close();

        return retVal;
    }
}

Calling method

public List<Category> GetAllActiveCategories(Guid siteGuid) {
    return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid).Result;
}

Everything looks in order to me. I have the method declaration decorated with the async keyword. I am awaiting on asynchronous methods.

The problem that I am having is that the thread blocks on await myCon.OpenAsync(); . This is my first attempt at using async and await, so I am sure that I am doing something wrong, but it is not obvious. Please help!

The posted Read code is fine. The issue is in the consuming code. It's common to get a deadlock with async if you call Wait() or Result on the returned Task or its antecedent Task up in the call chain.

As always in these cases, the general advice applies: don't block on async code . Once you start using async/await , you should be using async/await throughout your entire call chain.

So, your calling method becomes

public Task<List<Category>> GetAllActiveCategoriesAsync(Guid siteGuid) {
    return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid);
}

... or

public async Task<List<Category>> GetAllActiveCategoriesAsync(Guid siteGuid) {
    List<Category> result = await base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid);

    // Do something.

    return result;
}

The culprit is:

return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid).Result;

As Kirill noted, any time you use .Wait() or .Result on a Task, you are blocking synchronously. What you need to do is this:

public Task<List<Category>> GetAllActiveCategories(Guid siteGuid) {
    return base.Read<Category>(SPNAME_GETALLACTIVE, siteGuid);
}

This will return a Task to the calling method of this method, and so on... it has to be async "all the way up".

If the top-level consumer of this code is ASP.NET, you're fine. Just return a Task<IActionResult> (or the appropriate return type wrapped in a Task) and the framework will sort out the await ing for you.

If you're writing a console application or otherwise can't make it "async all the way up", you'll have to either block on .Result or make your method async void and use await . Neither one is a great solution, sadly. Async/await is pretty aggressive in the sense that you really do have to use it throughout your stack.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM