bloqueando el hilo principal en async / await

.net async-await asynchronous c# dapper

Pregunta

Estoy tratando de hacer que mi clase de repositorio base sea asíncrona y me encuentro en problemas. Estoy usando Dapper ORM en mi aplicación C #.

Método base

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;
    }
}

Método de llamada

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

Todo se ve bien para mí. Tengo la declaración del método decorada con la palabra clave async. Estoy esperando métodos asincrónicos.

El problema que estoy teniendo es que el hilo bloquea en await myCon.OpenAsync(); . Este es mi primer intento de usar asincronización y esperar, por lo que estoy seguro de que estoy haciendo algo mal, pero no es obvio. ¡Por favor ayuda!

Respuesta aceptada

El código de lectura publicado está bien. El problema está en el código de consumo. Es común encontrar un punto muerto con async si llama a Wait() o Result on the Returned Task o su antecedente Task up en la cadena de llamadas.

Como siempre en estos casos, se aplica el consejo general: no bloquee el código asíncrono . Una vez que empiece a usar async/await , debe usar async/await toda su cadena de llamadas.

Entonces, su método de llamada se convierte

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

... o

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

    // Do something.

    return result;
}

Respuesta popular

El culpable es:

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

Como señaló Kirill, cada vez que usa .Wait() o .Result on a Task, está bloqueando sincrónicamente. Lo que debes hacer es esto:

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

Esto devolverá una tarea al método de llamada de este método, y así sucesivamente ... tiene que ser asincrónico "completamente ascendente".

Si el consumidor de nivel superior de este código es ASP.NET, está bien. Simplemente devuelva una Task<IActionResult> (o el tipo de devolución apropiado Task<IActionResult> en una tarea) y el marco resolverá la await por usted.

Si está escribiendo una aplicación de consola o no puede hacerlo "asincrónico hasta el final", tendrá que bloquear en .Result o hacer que su método no sea async void y usar await . Ninguno de los dos es una gran solución, por desgracia. Async / await es bastante agresivo en el sentido de que realmente tienes que usarlo en toda tu pila.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué