c# - ejemplos - Llamando al método asíncrono al hacer clic en el botón



como usar async en c# (2)

Creé el proyecto de Windows Phone 8.1 y estoy tratando de ejecutar el método async GetResponse (url de cadena) al hacer clic en el botón y esperar a que el método termine, pero el método nunca termina. Aquí está mi código:

private void Button_Click(object sender, RoutedEventArgs 
{
      Task<List<MyObject>> task = GetResponse<MyObject>("my url");
      task.Wait();
      var items = task.Result; //break point here
}

public static async Task<List<T>> GetResponse<T>(string url)
{
    List<T> items = null;
    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);

    var response = (HttpWebResponse)await Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
    try
    {
        Stream stream = response.GetResponseStream();
        StreamReader strReader = new StreamReader(stream);
        string text = strReader.ReadToEnd();
        items = JsonConvert.DeserializeObject<List<T>>(text);
    }
    catch (WebException)
    {
        throw;
    }
    return items;
}

Se mantendrá en la tarea. Espera ().

Cambié mi método de clic de botón a asincrónico y lo usé en espera antes del método async y obtengo el resultado ( await GetResponse<string>("url") ). ¿Qué pasa con la Task<List<string>> task = GetResponse<string>("url") ? ¿Qué estoy haciendo mal?

¡Gracias por la ayuda!


Answer #1

Eres la víctima del punto muerto clásico. task.Wait() o task.Result es una llamada de bloqueo en el hilo de UI que causa el interbloqueo.

No bloquee en el hilo de UI . Nunca hacerlo. Solo aguardelo

private async void Button_Click(object sender, RoutedEventArgs 
{
      var task = GetResponseAsync<MyObject>("my url");
      var items = await task;
}

Por cierto, ¿por qué estás atrapando la WebException y tirándola de vuelta? Sería mejor si simplemente no lo atrapa. Ambos son lo mismo.

También puedo ver que estás mezclando el código asíncrono con código síncrono dentro del método GetResponse . StreamReader.ReadToEnd es una llamada de bloqueo --usted debe usar StreamReader.ReadToEndAsync .

También use el sufijo "Async" para los métodos que devuelve una tarea o asincrónico para seguir la convención TAP ("Asynchronous Pattern asincrónico") como dice Jon .

Su método debe verse de la siguiente manera cuando haya tratado todas las inquietudes anteriores.

public static async Task<List<T>> GetResponseAsync<T>(string url)
{
    HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
    var response = (HttpWebResponse)await Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);

    Stream stream = response.GetResponseStream();
    StreamReader strReader = new StreamReader(stream);
    string text = await strReader.ReadToEndAsync();

    return JsonConvert.DeserializeObject<List<T>>(text);
}

Answer #2

Esto es lo que te está matando:

task.Wait();

Eso está bloqueando el hilo de la interfaz de usuario hasta que la tarea se haya completado, pero la tarea es un método asíncrono que intentará volver al hilo de la interfaz de usuario después de que se "pause" y espere un resultado de sincronización. No puede hacer eso, porque estás bloqueando el hilo de UI ...

No hay nada en su código que realmente parezca tener que estar en el hilo de la IU de todos modos, pero suponiendo que realmente lo quiere allí, debe usar:

private async void Button_Click(object sender, RoutedEventArgs 
{
    Task<List<MyObject>> task = GetResponse<MyObject>("my url");
    var items = await task;
    // Presumably use items here
}

O solo:

private async void Button_Click(object sender, RoutedEventArgs 
{
    var items = await GetResponse<MyObject>("my url");
    // Presumably use items here
}

Ahora, en lugar de bloquear hasta que la tarea se haya completado, el método Button_Click volverá luego de programar una continuación para disparar cuando la tarea se haya completado. (Así es como funciona async / await, básicamente).

Tenga en cuenta que también cambiaría el nombre de GetResponse a GetResponseAsync para mayor claridad.





asynchronous