1

私は WCF サービス アプリケーションを作成しましたが、基本的に名前以外は何も変更していません。デフォルトのコントラクトがありGetData(Int32)、文字列を返すメソッドが含まれています。

次に、.NET FW 4.5をターゲットとするWPF クライアントアプリケーションを作成したので、そのサービスへのサービス参照を追加する場所で、生成されたサービス クライアントにコントラクト メソッドのタスク ベースの非同期バリアントを含めることを選択できます。

サービスを利用しようとすると、次のようになります。

  using (var client = new RhaeoServiceClient())
  {
    client.GetDataAsync(17).ContinueWith(t => MessageBox.Show(t.Result));
    MessageBox.Show("inb4");
  }

ボタンクリックハンドラーから実行すると、ウィンドウが停止し、ボタンが1秒ほど押されたままになり、"inb4" メッセージが表示されるため、タスクがメインスレッドで実行されてネットワークを待機し、UIがフリーズするようです。

クリックしてもすぐには"inb4"表示されず、タスクが実行された後、私が言ったように1〜2秒待っているようです。ショーの後"inb4"、結果が表示された次のメッセージボックスも表示されますが、面白いのは、次のメッセージボックスが最初のメッセージボックスを閉じるのを待たずに、最初のメッセージボックスが表示された直後に最初のメッセージボックスにポップすることです。

継続コードが実際には別のスレッドで実行され、メイン スレッドが最初のメッセージ ボックスによってブロックされていることを気にしないように見えるため、これは混乱を招きます。しかし、UI スレッドからしか表示できないメッセージ ボックスをどのように表示するのでしょうか (そうですか?)。

また、タスクの実行後に最初のメッセージ ボックスが待機し、表示され、閉じられずに次のメッセージ ボックスが表示されるのはなぜですか?

4

1 に答える 1

0

t.Result は、Task が完了するまで呼び出しスレッドをブロックします。WCF 呼び出しと組み合わせて async/await キーワードを使用すると、必要な結果を得ることができます。

    private void button1_Click(object sender, EventArgs e)
    {
        CallGetDataAsync(17);
        MessageBox.Show("inb4");
    }

    private async void CallGetDataAsync(int number)
    {
        string result = null;

        var client = new Service1Client();
        try
        {
            // After this line, control is returned to the calling method; the ConfigureAwait(true) 
            // explicitly indicates that when execution resumes, it should attempt to marshall back
            // to the calling thread.  If you change it to false, you can see that the subsequent
            // messagebox does not stop you from interacting with your main form.
            result = await client.GetDataAsync(number).ConfigureAwait(true);

            // when the async service call completes, execution will resume here
            client.Close();
        }
        catch
        {
            try
            {
                client.Close();
            }
            catch
            {
                client.Abort();
            }
            throw;
        }

        // display the MessageBox, this should block the UI thread 
        MessageBox.Show(result);
    }

クライアントと同じマシンで実行されているサービスに対してこれを実行すると、WCF サービス呼び出しがサービス結果メッセージの後に「inb4」がまだ表示されるほど速く返されるため、何が起こっているのかを確認するのは困難です。サンプル サービス メソッドに遅延を入れると、動作がわかりやすくなります。

    public string GetData(int value)
    {
        return Task.Delay(TimeSpan.FromSeconds(5)).ContinueWith(_ => string.Format("You entered: {0}", value)).Result;
    }

最後の質問ですが、MessageBox はバックグラウンド スレッドから呼び出すことができます。ただし、モーダルとして機能せず、メイン フォームをブロックします。

于 2013-10-05T23:15:08.210 に答える