2

WebRequest オブジェクトで非同期呼び出しを使用するための次の拡張メソッドがあります。

 public static Task<WebResponse> GetReponseAsync(this WebRequest request)
    {
        return Task.Factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
    }

    public static Task<Stream> GetRequestStreamAsync(this WebRequest request)
    {
        return Task.Factory.FromAsync<Stream>(request.BeginGetRequestStream, request.EndGetRequestStream, null);
    }

これらの拡張メソッドを使用して、次のコードを同等の非同期コードに変換したいと思います。

using (Stream rs = request.GetRequestStream())
{
   var postData = Encoding.ASCII.GetBytes(PostData);
   rs.Write(postData, 0, postData.Length);

   using (WebResponse response = request.GetResponse())
   using (StreamReader reader = new StreamReader(response.GetResponseStream()))
   {
       str = reader.ReadToEnd();

       rs.Close();
       reader.Close();
       response.Close();
   }
}

これは、WebRequest を使用する別のコードを使用して簡単に実行できましたが、最初に GetRequestStream() を呼び出す必要はありませんでした。

request.GetReponseAsync().ContinueWith(t =>
{
    if (t.Exception == null)
    {
        using (var sr = new StreamReader(t.Result.GetResponseStream()))
        {
            str = sr.ReadToEnd();
        }
    }
});

最初のコード ブロックを変換して拡張メソッドを使用し、同等にするにはどうすればよいですか?

EDIT私は.NET 4.0を使用しているため、現在async/awaitはオプションではありません。

4

1 に答える 1

3

ContinueWith呼び出しをチェーンするだけです。経験則として、シーケンス内の非同期操作ごとに 1 つの ContinueWith があります。通常、各 ContinueWith は で終了しreturn <some async call>、次はその結果の処理を開始します。

request.GetRequestStreamAsync()
       .ContinueWith((trs) =>
           {
               var postData = System.Text.Encoding.ASCII.GetBytes("dummy");
               trs.Result.Write(postData, 0, postData.Length);
               return request.GetResponseAsync();
           }).Unwrap()
       .ContinueWith((resp) =>
           {
               using (var sr = new StreamReader(resp.Result.GetResponseStream()))
               {
                   var str = sr.ReadToEnd();
               }
           });

私のコード (および非同期バージョン) では、すべてのオブジェクトが元のように破棄されているわけではないことに注意してください。

各ステップで、おそらく Status または IsFaulted/IsCanceled プロパティを確認するか、TaskContinuationOptions パラメーターを受け取る ContinueWith のオーバーロードを使用する必要があります。後者のオプションの場合、前のタスクがオプションと一致する方法で完了しないと、タスクがキャンセルされることに注意してください。エラーを通過させる必要がある場合、そのアプローチはそうではありません。個人的には、エラーとキャンセルを通過するか、正常に完了したときにデリゲートを実行するメソッドにすべてのチェックをラップします。そうしないと、大量のボイラープレート チェック コードがすぐに取得されてしまいます。

于 2013-07-16T05:28:48.120 に答える