net mvc example await async asp c# asp.net-mvc asp.net-web-api async-await

c# - mvc - web api async controller



Utilice efectivamente async/await con API web ASP.NET (4)

No estoy muy seguro de si habrá alguna diferencia en el rendimiento de mi API.

Tenga en cuenta que el beneficio principal del código asincrónico en el lado del servidor es la escalabilidad . No hará que sus solicitudes se ejecuten mágicamente más rápido. Cubro varias consideraciones sobre "debería usar async " en mi artículo sobre ASP.NET async .

Creo que su caso de uso (llamar a otras API) es adecuado para el código asincrónico, solo tenga en cuenta que "asincrónico" no significa "más rápido". El mejor enfoque es primero hacer que su IU responda y sea asíncrona; esto hará que tu aplicación se sienta más rápida incluso si es un poco más lenta.

En lo que respecta al código, esto no es asíncrono:

public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries() { var response = _service.Process<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries"); return Task.FromResult(response); }

Necesitaría una implementación verdaderamente asincrónica para obtener los beneficios de escalabilidad de async :

public async Task<BackOfficeResponse<List<Country>>> ReturnAllCountriesAsync() { return await _service.ProcessAsync<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries"); }

O (si su lógica en este método realmente es solo un paso):

public Task<BackOfficeResponse<List<Country>>> ReturnAllCountriesAsync() { return _service.ProcessAsync<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries"); }

Tenga en cuenta que es más fácil trabajar desde "adentro hacia afuera" que desde "afuera hacia adentro" de esta manera. En otras palabras, no comience con una acción de controlador asíncrono y luego fuerce los métodos posteriores para que sean asíncronos. En su lugar, identifique las operaciones naturalmente asíncronas (llamadas a API externas, consultas de bases de datos, etc.), y haga que sean asíncronas en el nivel más bajo primero ( Service.ProcessAsync ). Luego, deje que se async la async , haciendo que las acciones de su controlador sean asíncronas como el último paso.

Y bajo ninguna circunstancia debe usar Task.Run en este escenario.

Estoy tratando de hacer uso de la función async/await de ASP.NET en mi proyecto de API web. No estoy muy seguro de si habrá alguna diferencia en el rendimiento de mi servicio de API web. A continuación encontrará el flujo de trabajo y el código de muestra de mi aplicación.

Flujo de trabajo:

Aplicación de IU → Punto final de API web (controlador) → Método de llamada en la capa de servicio de API web → Llamar a otro servicio web externo. (Aquí tenemos las interacciones DB, etc.)

Controlador:

public async Task<IHttpActionResult> GetCountries() { var allCountrys = await CountryDataService.ReturnAllCountries(); if (allCountrys.Success) { return Ok(allCountrys.Domain); } return InternalServerError(); }

Capa de servicio:

public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries() { var response = _service.Process<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries"); return Task.FromResult(response); }

Probé el código anterior y está funcionando. Pero no estoy seguro de si es el uso correcto de async/await . Por favor comparte tus pensamientos.


Cambiaría su capa de servicio a:

public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries() { return Task.Run(() => { return _service.Process<List<Country>>(BackOfficeEndpoint.CountryEndpoint, "returnCountries"); } }

tal como lo tiene, todavía está ejecutando su _service.Process call sincrónicamente, y obtiene muy poco o ningún beneficio de esperarlo.

Con este enfoque, está envolviendo la llamada potencialmente lenta en una Task , iniciándola y devolviéndola para que la espere. Ahora obtienes el beneficio de esperar la Task .


Es correcto, pero quizás no sea útil.

Como no hay nada que esperar, no hay llamadas a las API de bloqueo que podrían funcionar de forma asíncrona, entonces está configurando estructuras para rastrear la operación asincrónica (que tiene sobrecarga) pero no está haciendo uso de esa capacidad.

Por ejemplo, si la capa de servicio realizaba operaciones de base de datos con Entity Framework que admite llamadas asincrónicas:

public Task<BackOfficeResponse<List<Country>>> ReturnAllCountries() { using (db = myDBContext.Get()) { var list = await db.Countries.Where(condition).ToListAsync(); return list; } }

Permitiría que el subproceso de trabajo haga otra cosa mientras se consulta la base de datos (y, por lo tanto, puede procesar otra solicitud).

Aguardar tiende a ser algo que tiene que llegar hasta el final: es muy difícil volver a encajar en un sistema existente.


No está aprovechando async / await efectivamente porque el hilo de solicitud se bloqueará mientras se ejecuta el método sincrónico ReturnAllCountries()

El subproceso que se asigna para manejar una solicitud estará inactivo esperando mientras ReturnAllCountries() hace su trabajo.

Si puede implementar ReturnAllCountries() para que sea asíncrono, verá beneficios de escalabilidad. Esto se debe a que el subproceso podría devolverse al grupo de subprocesos .NET para manejar otra solicitud, mientras se ejecuta ReturnAllCountries() . Esto permitiría que su servicio tenga un mayor rendimiento al utilizar subprocesos de manera más eficiente.