Async - espera todo el camino -- # campo con async-await campo con asp.net-web-api camp codereview Relacionados El problema

Async - await all the way


0
vote

problema

Español

relacionado con este Pregunta (e incluso Esta pila de desbordamiento es una ) He estado tratando de evitar bloquear el código. Entonces, lo que entendí es que es preferible hacer todos los métodos que se basan en un Async One Async. Por lo tanto, he cambiado mi código para hacer lo siguiente (incluyo aquí más "capas" que en las preguntas que vinculé, ya que tuve que cambiar en consecuencia esas).

Mi API, exponiendo un método:

  [Route("api/postconfiguration")] public async Task<IHttpActionResult> PostConfiguration(configurationData configurationData) {     try     {         await _configurationRequestHandler.HandlePostRequest(configurationData);         return Ok();     }     catch (Exception e)     {         // Log error         return InternalServerError(e);     } }   

que utiliza este método:

  public async Task HandlePostRequest(Data Data) {     var configuration = await _ConfigurationService.GetConfigurationAsync(Data.AgentId);      // Use that configuration }   

y este sería el método llamando a la API externa

  public class ConfigurationApiClient : IConfigurationService {     private readonly HttpClient _client;     private const string resourcePath = "configuration/{0}";      public ConfigurationApiClient(IConfigurationManager configurationManager)     {         _client = new HttpClient();         _client.BaseAddress = new Uri(configurationManager.GetAppSetting("ConfigurationApiUrl"));         _client.DefaultRequestHeaders.Accept.Clear();         _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));     }      public async Task<Configuration> GetConfigurationAsync(int agentId)     {         try         {             var response = await _client.GetAsync(String.Format(resourcePath, agentId));             response.EnsureSuccessStatusCode();             return await response.Content.ReadAsAsync<Configuration>();         }         catch (HttpRequestException ex)         {             throw new Exception(string.Format("Exception when getting  configuration for agent: {0}", agentId), ex);         }     }  }   

Esta es mi comprensión de lo que debería hacer por hacerlo asíncrono, pero agradecería que alguien me apunta cualquier error.

Estoy usando la API en un cliente, que hace esto:

  public async Task DeployConfiguration(Package package, EFEnvironment environment) {     using (var client = new HttpClient())     {         // Prepare the configurationData          var agentTasks = agents.Select(a =>             {                 var configurationPostRequest = new ConfigurationData                     {                         // Create it                     };                  return client.PostAsJsonAsync("api/postconfiguration", configurationPostRequest);             });          await Task.WhenAll(agentTasks);     } }   

que se llama dentro de un método de sincronización:

  _deployApiService.DeployConfiguration(package, environment);   
Original en ingles

Related to this question (and even this Stack Overflow's one) I have been trying to avoid blocking the code. So what I understood it's that is preferable to make all the methods that rely on an async one async themselve (thus not defeating the purpose of asynchronous). Therefore I have changed my code to do the following (I include here more "layers" than in the questions I linked as I had to change accordingly those).

My API, exposing a method:

[Route("api/postconfiguration")] public async Task<IHttpActionResult> PostConfiguration(configurationData configurationData) {     try     {         await _configurationRequestHandler.HandlePostRequest(configurationData);         return Ok();     }     catch (Exception e)     {         // Log error         return InternalServerError(e);     } } 

That uses this method:

public async Task HandlePostRequest(Data Data) {     var configuration = await _ConfigurationService.GetConfigurationAsync(Data.AgentId);      // Use that configuration } 

And this would be the method calling the external api

public class ConfigurationApiClient : IConfigurationService {     private readonly HttpClient _client;     private const string resourcePath = "configuration/{0}";      public ConfigurationApiClient(IConfigurationManager configurationManager)     {         _client = new HttpClient();         _client.BaseAddress = new Uri(configurationManager.GetAppSetting("ConfigurationApiUrl"));         _client.DefaultRequestHeaders.Accept.Clear();         _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));     }      public async Task<Configuration> GetConfigurationAsync(int agentId)     {         try         {             var response = await _client.GetAsync(String.Format(resourcePath, agentId));             response.EnsureSuccessStatusCode();             return await response.Content.ReadAsAsync<Configuration>();         }         catch (HttpRequestException ex)         {             throw new Exception(string.Format("Exception when getting  configuration for agent: {0}", agentId), ex);         }     }  } 

This is my understanding of what I should do for making it asynchronous, but would appreciate if someone points me any error.

I am using the API on one client myself, which does this:

public async Task DeployConfiguration(Package package, EFEnvironment environment) {     using (var client = new HttpClient())     {         // Prepare the configurationData          var agentTasks = agents.Select(a =>             {                 var configurationPostRequest = new ConfigurationData                     {                         // Create it                     };                  return client.PostAsJsonAsync("api/postconfiguration", configurationPostRequest);             });          await Task.WhenAll(agentTasks);     } } 

Which is just called inside a sync method:

_deployApiService.DeployConfiguration(package, environment); 
        

Lista de respuestas

1
 
vote
vote
La mejor respuesta
 

Su código cae en una trampa clásica, que IMO es un error de diseño de Microsoft. 99% del tiempo, await Foo(); debe ser await Foo().ConfigureAwait(false); . El guía semi-oficial es

Para resumir esta tercera guía, debe usar Configure­Await cuando sea posible. El código libre de contexto tiene un mejor rendimiento para las aplicaciones GUI y es una técnica útil para evitar los puntos muertos cuando se trabaja con una base de código parcialmente ASYC. Las excepciones a esta guía son métodos que requieren el contexto.

Creo que hubiera sido mucho mejor para ConfigureAwait(false) para ser el predeterminado y requerir ConfigureAwait(true) en aquellos casos que requieren el contexto, pero ahora es demasiado tarde para Microsoft Para cambiar esto, por lo que todos deberíamos contactar con el hábito de usar ConfigureAwait(false) de forma predeterminada y en aquellos casos raros que documentan el motivo de dejarlo (o incluso usar ConfigureAwait(true) y suplementándolo con un comentario que da la razón).

 

Your code falls into a classic trap, which IMO is a design error by Microsoft. 99% of the time, await Foo(); should be await Foo().ConfigureAwait(false);. The semi-official guidance is

To summarize this third guideline, you should use Configurexc2xadAwait when possible. Context-free code has better performance for GUI applications and is a useful technique for avoiding deadlocks when working with a partially async codebase. The exceptions to this guideline are methods that require the context.

I think that it would have been far better for ConfigureAwait(false) to be the default and to require ConfigureAwait(true) in those cases which require context, but it's too late now for Microsoft to change this, so we should all get into the habit of using ConfigureAwait(false) by default and in those rare cases documenting the reason for leaving it off (or even explicitly using ConfigureAwait(true) and supplementing it with a comment which gives the reason).

 
 
   
   
0
 
vote

Desde mi comprensión de ASP.NET ASYNC / AWAIT, AWAITING no devuelve el control al método de llamada, devolverá el hilo de la solicitud al grupo de hilos, lo que le permitirá usarlo para otras solicitudes. Solo debe tener que tener una espera en las llamadas de bloqueo en la parte inferior.

 

From my understanding of ASP.NET async/await, awaiting doesn't return control to the calling method, it will return the request thread to the thread pool, allowing it to be used for other requests. You should only need to have an await on the blocking calls at the very bottom.

 
 
     
     

Relacionados problema

2  Los grupos de seguridad de Active Directory buscan la optimización de la aplicación  ( Active directory security groups search application optimization ) 
Tengo un método de API web que devuelve los grupos de seguridad de Active Directory para el usuario de inicio de sesión específico. El siguiente código estaba...

2  Diferente enfoque a la siguiente acción ASP.NET WEB API  ( Different approach to the following asp net web api action ) 
Tal vez alguien aquí puede ayudarme a resolver esta implementación y hacerlo mejor. Primero las siguientes restricciones: 1 controlador & amp; Acción que...

2  Seguridad de la inyección de la dependencia  ( Dependency injection thread safety ) 
¿Está bien mezclar diferentes por vida de ISerializer y ICacheProvider en este caso? Estoy usando unity di. En este caso, cada vez que se necesita ICache...

7  Handler de mensajes de token de autenticación básica  ( Basic authentication token message handler ) 
Ordinariamente estoy bastante seguro en mi propio código, pero al ver cómo esto se refiere a la seguridad y no quiero haber pasado por alto nada que pueda cau...

0  Usando RabbitMQ en ASP.NET WEB API  ( Using rabbitmq in asp net web api ) 
use caso : Tengo una API web de pedido que crea órdenes y publica la orden de la cola de mensajería. El servicio de notificación (API 2 web) consume este me...

1  Usando el negociador personalizado y el formateador personalizado en Web API 2  ( Using custom negotiator and custom formatter in web api 2 ) 
Aquí está mi formateador personalizado que quiero usar para " application / x.Product " Tipo de contenido: public class ProductFormatter : MediaTypeFormatt...

2  Objeto de búsqueda de la base de datos, o fetchlo usando una API si no está ahí  ( Fetch object from database or fetch it using an api if it isnt there ) 
Para dar algunos antecedentes en este código en particular, hay un controlador que recibe un objeto, las partes de los hashes y se analiza en una base de dato...

14  Cómo transmitir datos directamente desde la base de datos a través de una arquitectura de 3 niveles  ( How to stream data directly from the database through a 3 tier architecture ) 
El problema: generar un archivo CSV que se almacena demasiado grande en la memoria en una arquitectura de 3 niveles, sin la complejidad de guardar el archivo ...

6  API web utilizando repositorio / unitofwork  ( Web api using repository unitofwork ) 
Estoy buscando comentarios en un repositorio que configuré en función de una publicación de blog, leí aquí . Recientemente he tenido más tiempo en .NET en ...

3  ¿Es correcta mi arquitectura N-tier de esta aplicación web?  ( Is my n tier architecture of this web api correct ) 
Estoy haciendo una API web usando la API web 2. Tengo tres capas: Business - Tiendas Modelos y clases de servicio. datos - solo ef. Actualmente una dB. P...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos