2013-08-10 5 views
11

私は同期メソッドをいくつかの古いコードから非同期メソッドに変えようとしています、何かトラブルがあると分かります。私が読んだすべてのビデオとチュートリアルから、それらはメソッドに作成されているように見えますが、実際の関数ともう1つのラッパーは、UIで呼び出されるラッパーです。私はいくつかの古いコードから非同期メソッドに同期メソッドを有効にしようとしていますが、いくつかの問題を理解しています

はここに私のコードです:私はボタンクリックからUIスレッド上のメソッドを呼び出すしようとすると、

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

何らかの理由で、ボタンイベントの非同期を作るために私を求めています。

txtLog.AppendText("Before Await"); 

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

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

また、asyncに設定されてログインを呼び出すラッパーメソッドが必要ですか?

これはすべて少し複雑です。

答えて

13

ボタンasyncのイベントをマークする必要があります。awaitというキーワードをコード内で使用する場合は、関数asyncを宣言する必要があります。

を使用せずに関数がasyncを使用する場合、コードは非同期では実行されません。タスクを作成し、その中に同期メソッドを実行するか、メソッドを非同期に書き直す必要があります。関数法書き換え

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

:タスク方法として

私がやっている何を私の "書き換え方法" で

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

は私がExecuteAsync魔女を使用していますですpart of IRestClientです。この関数は、完了時にコールバックメソッドを呼び出します。コールバックメソッドでは、tcsSetResultを呼び出して、必要な結果をレポートします。

あなたは私たちがこれを行う場合、我々はクリーンアップすることができますので、しかし、我々は関数に戻っ asyncを持参する必要があるとの結果を待って、 CancellationTokenにトークンが RestRequestAsyncHandleにコール Abort()を提起された場合にとることで、これをさらに拡大でき

キャンセルトークン登録後。

private Task<bool> login(String username, String password) 
{ 
    return login(username, password, CancellationToken.None); 
} 

private async Task<bool> login(String username, String password, CancellationToken cancelToken) 
{ 
    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); 

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

       tcs.TrySetResult(dom["html"].HasClass("logged-in")); 
      } 
      catch(Exception ex) 
      { 
       tcs.TrySetException(ex); 
      } 
     }); 

    //if the token is canceled it will call `asyncHandle.Abort()` for us. 
    using(cancelToken.Register(() => 
     { 
      if(tcs.TrySetCanceled(cancelToken)) 
       asyncHandle.Abort(); 
     })) 
    { 
     return await tcs.Task; 
    } 
} 
+0

Scott私はちょうどExecuteAsyncの使い方を調べていて、使い方が分かりませんでした。また、 "HasClass"メソッドを持つCsQueryを使用していました。 –

+0

私はキャンセル可能なバージョンでいくつか調整を行いました。ジョブがキャンセルされたことを 'tcs'に通知する必要があります。また、コールバックにスローされる可能性のある例外を報告するサポートを追加しました。 –

+0

この回答は私にとって有益です。ありがとうございました。 –

1

ボタンハンドラはawaitキーワードを使用します。この場合、asyncにする必要があります。 awaitキーワードは、基本的にメソッドをawaitに分割し、awaitの後の部分を代理人に変えて、待ち受けているTaskが完了すると続行します。メソッドはawaitに遭遇した直後に戻ります。

あなたのログイン機能はawaitを使用していません。 asyncというキーワードは必要ありません。

関連する問題