2013-08-10 3 views
11

Sto provando a trasformare un metodo sincrono da un vecchio codice in un metodo asincrono, ma I ' Ho qualche problema a capire. Da tutti i video e le esercitazioni che ho letto sembrano creare dei metodi, uno la funzione vera e propria, l'altro un wrapper e quindi il wrapper chiamato sull'interfaccia utente.Sto provando a trasformare un metodo sincrono da un vecchio codice in un metodo asincrono, ma ho qualche problema a capire

Ecco il mio codice:

private async Task<bool> login(String username, String password) 
{ 
     var tcs = new TaskCompletionSource<RestSharp.IRestResponse>(); 

     RestSharp.RestRequest request = new RestSharp.RestRequest("/accounts/login/", RestSharp.Method.GET); 
     RestSharp.IRestResponse response = client.Execute(request); 

     // Make the login request 
     request = new RestSharp.RestRequest("/accounts/login/", RestSharp.Method.POST); 
     request.AddParameter("username", username); 
     request.AddParameter("password", password); 

     response = client.Execute(request); 

     // Return loggin status 
     dom = response.Content; 
     return dom["html"].HasClass("logged-in"); 
} 

Per qualche ragione quando provo a chiamare il metodo sul thread UI da un clic del pulsante, mi sta chiedendo di rendere l'evento asincrono pulsante.

txtLog.AppendText("Before Await"); 

Task<bool> result = await login("",""); 

txtLog.AppendText("After Await"); 
txtLog.AppendText("Result: " + result.toString()); 

Ho bisogno di un metodo wrapper che sia anche impostato su async che rende la chiamata di accesso?

Tutto ciò sembra un po 'complesso.

risposta

13

Per rispondere alla tua seconda parte prima, sì è necessario marcare l'evento per il pulsante async, se si desidera utilizzare la parola chiave await nel codice è necessario dichiarare la funzione async.

2ndly se una funzione usa async senza avere un await all'interno di esso il codice non verrà eseguito in modo asincrono, si sia bisogno di creare un'attività ed eseguire il metodo sincrono all'interno di esso o riscrivere il metodo di essere asincrono.

come metodo di lavoro:

private async void button1_Click(object sender, EventArgs e) 
{ 
    txtLog.AppendText("Before Await"); 

    //Note I changed from "Task<bool>" to "bool", await is like calling ".Result" 
    // on a task but not blocking the UI, so you store the type you are waiting for. 
    bool result = await Task.Run(() => login("","")); //You would still use your old login code before you tried to make it async, it requires no modifications. 

    txtLog.AppendText("After Await"); 
    txtLog.AppendText("Result: " + result.ToString()); 
} 

riscrittura metodo della funzione:

private async void button1_Click(object sender, EventArgs e) 
{ 
    txtLog.AppendText("Before Await"); 

    //Note I changed from "Task<bool>" to "bool", await is like calling ".Result" 
    // on a task but not blocking the UI, so you store the type you are waiting for. 
    bool result = await login("",""); 

    txtLog.AppendText("After Await"); 
    txtLog.AppendText("Result: " + result.ToString()); 
} 

private Task<bool> login(String username, String password) 
{ 
    var tcs = new TaskCompletionSource<bool>(); 

    // Make the login request 
    var request = new RestSharp.RestRequest("/accounts/login/", RestSharp.Method.POST); 
    request.AddParameter("username", username); 
    request.AddParameter("password", password); 

    client.ExecuteAsync(request, (response, handle) => 
     { 
      try 
      { 
       // Return loggin status 
       var dom = response.Content; 

       //dom["html"] did not have a .HasClass in my tests, so this code may need work. 
       tcs.TrySetResult(dom["html"].HasClass("logged-in")); 
      } 
      catch(Exception ex) 
      { 
       tcs.TrySetException(ex); 
      } 
     }); 

    return tcs.Task; 
} 

Nel mio "metodo di riscrittura" quello che sto facendo è che sto usando ExecuteAsync strega è part of IRestClient. Quella funzione chiama un metodo di callback quando viene completato, nel metodo di callback chiamo tcs di SetResult per segnalare il risultato che volevo.

Si potrebbe ampliare ulteriormente questo prendendo in CancellationToken e se il token è sollevata chiamata Abort() su RestRequestAsyncHandle, se facciamo questo abbiamo bisogno di portare il async nuovamente a funzione e attendiamo il risultato in modo che possiamo ripulire dopo la registrazione del token di cancellazione.

+0

Scott hai appena risposto a due domande in una per me perché stavo solo cercando di usare ExecuteAsync e mi sono confuso su come usarlo. Inoltre, stavo usando CsQuery che ha il metodo "HasClass". –

+0

Ho apportato alcune modifiche alla versione cancellabile, è necessario notificare a 'tcs' che il lavoro è stato annullato.Ho anche aggiunto il supporto per la segnalazione di eventuali eccezioni che potrebbero essere lanciate sul callback. –

+0

Questa risposta è utile per me. Grazie. –

1

Il gestore del pulsante utilizza la parola chiave await, che richiede che venga effettuata async. La parola chiave await divide in pratica il metodo allo await, trasformando la parte dopo lo await in un delegato che continua quando l'attesa Task completa. Il metodo restituisce immediatamente dopo l'incontro con lo await.

La funzione di login non utilizza await. Non ha bisogno della parola chiave async.

Problemi correlati