チュートリアル: Async と Await を使用した Web へのアクセス (C#)Walkthrough: Accessing the Web by Using async and await (C#)

async/await 機能を使用することで、非同期プログラムをより簡単かつ直感的に記述できます。You can write asynchronous programs more easily and intuitively by using async/await features. 同期コードに似た非同期コードを記述し、通常の非同期コードが必要とする難しいコールバック関数や継続の処理をコンパイラに任せます。You can write asynchronous code that looks like synchronous code and let the compiler handle the difficult callback functions and continuations that asynchronous code usually entails.

非同期機能について詳しくは、「Async および Await を使用した非同期プログラミング (C# および Visual Basic)」をご覧ください。For more information about the Async feature, see Asynchronous Programming with async and await (C#).

このチュートリアルは、Web サイトの一覧でのバイト数の合計を計算する同期 Windows Presentation Foundation (WPF) アプリケーションから開始します。This walkthrough starts with a synchronous Windows Presentation Foundation (WPF) application that sums the number of bytes in a list of websites. その後、新しい機能を使用して、アプリケーションを非同期ソリューションに変換します。The walkthrough then converts the application to an asynchronous solution by using the new features.

自分でアプリケーションを作成しない場合は、非同期サンプル: Web へのアクセスのチュートリアル (C# および Visual Basic) をダウンロードできます。If you don't want to build the applications yourself, you can download Async Sample: Accessing the Web Walkthrough (C# and Visual Basic).

このチュートリアルでは、次のタスクを行います。In this walkthrough, you complete the following tasks:

注意

この例を実行するには、コンピューターに Visual Studio 2012 以降および .NET Framework 4.5 以降がインストールされている必要があります。To run the examples, you must have Visual Studio 2012 or newer and the .NET Framework 4.5 or newer installed on your computer.

WPF アプリケーションを作成するにはTo create a WPF application

  1. Visual Studio を起動します。Start Visual Studio.

  2. メニュー バーで、 [ファイル][新規作成][プロジェクト] の順にクリックします。On the menu bar, choose File, New, Project.

    [新しいプロジェクト] ダイアログ ボックスが表示されます。The New Project dialog box opens.

  3. [インストールされたテンプレート] ウィンドウで、[Visual C#] をクリックし、プロジェクトの種類の一覧で [WPF アプリケーション] をクリックします。In the Installed Templates pane, choose Visual C#, and then choose WPF Application from the list of project types.

  4. [名前] ボックスに「AsyncExampleWPF」と入力して、[OK] を選択します。In the Name text box, enter AsyncExampleWPF, and then choose the OK button.

    ソリューション エクスプローラーに新しいプロジェクトが表示されます。The new project appears in Solution Explorer.

単純な WPF MainWindow をデザインするにはTo design a simple WPF MainWindow

  1. Visual Studio コード エディターで、 [MainWindow.xaml] タブをクリックします。In the Visual Studio Code Editor, choose the MainWindow.xaml tab.

  2. [ツールボックス] ウィンドウが表示されていない場合は、[表示] メニューを開き、[ツールボックス] をクリックします。If the Toolbox window isn’t visible, open the View menu, and then choose Toolbox.

  3. [Button] コントロールと [TextBox] コントロールを [MainWindow] ウィンドウに追加します。Add a Button control and a TextBox control to the MainWindow window.

  4. [TextBox] コントロールを強調表示し、[プロパティ] ウィンドウで次の値を設定します。Highlight the TextBox control and, in the Properties window, set the following values:

    • [Name] プロパティを resultsTextBox に設定します。Set the Name property to resultsTextBox.

    • [Height] プロパティを 250 に設定します。Set the Height property to 250.

    • [Width] プロパティを 500 に設定します。Set the Width property to 500.

    • [テキスト] タブで、Lucida Console や Global Monospace などの等幅フォントを指定します。On the Text tab, specify a monospaced font, such as Lucida Console or Global Monospace.

  5. [Button] コントロールを強調表示し、[プロパティ] ウィンドウで次の値を設定します。Highlight the Button control and, in the Properties window, set the following values:

    • [Name] プロパティを startButton に設定します。Set the Name property to startButton.

    • [Content] プロパティの値を [Button] から [Start] に変更します。Change the value of the Content property from Button to Start.

  6. テキスト ボックスとボタンの位置を調整し、両方が [MainWindow] ウィンドウ内に表示されるようにします。Position the text box and the button so that both appear in the MainWindow window.

    WPF XAML デザイナーについて詳しくは、「XAML デザイナーを使用した UI の作成」をご覧ください。For more information about the WPF XAML Designer, see Creating a UI by using XAML Designer.

参照を追加するにはTo add a reference

  1. ソリューション エクスプローラーで、プロジェクトの名前を強調表示します。In Solution Explorer, highlight your project's name.

  2. メニュー バーで、[プロジェクト][参照の追加] の順に選択します。On the menu bar, choose Project, Add Reference.

    [参照マネージャー] ダイアログ ボックスが表示されます。The Reference Manager dialog box appears.

  3. ダイアログ ボックスの上部で、プロジェクトのターゲットが .NET Framework 4.5 以上であることを確認します。At the top of the dialog box, verify that your project is targeting the .NET Framework 4.5 or higher.

  4. [アセンブリ] で、[フレームワーク] を選択します (選択されていない場合)。In the Assemblies area, choose Framework if it isn’t already chosen.

  5. 名前の一覧で、[System.Net.Http] のチェック ボックスをオンにします。In the list of names, select the System.Net.Http check box.

  6. [OK] をクリックしてダイアログ ボックスを閉じます。Choose the OK button to close the dialog box.

ディレクティブを使用して必要なものを追加するにはTo add necessary using directives

  1. ソリューション エクスプローラーで MainWindow.xaml.cs のショートカット メニューを開き、[コードの表示] を選択します。In Solution Explorer, open the shortcut menu for MainWindow.xaml.cs, and then choose View Code.

  2. 次の using ディレクティブが含まれていない場合は、コード ファイルの先頭に追加します。Add the following using directives at the top of the code file if they’re not already present.

    using System.Net.Http;  
    using System.Net;  
    using System.IO;  
    

同期アプリケーションを作成するにはTo create a synchronous application

  1. デザイン ウィンドウの MainWindow.xaml で、[Start] ボタンをダブルクリックして、MainWindow.xaml.cs に startButton_Click イベント ハンドラーを作成します。In the design window, MainWindow.xaml, double-click the Start button to create the startButton_Click event handler in MainWindow.xaml.cs.

  2. MainWindow.xaml.cs で、次のコードを startButton_Click の本文にコピーします。In MainWindow.xaml.cs, copy the following code into the body of startButton_Click:

    resultsTextBox.Clear();  
    SumPageSizes();  
    resultsTextBox.Text += "\r\nControl returned to startButton_Click.";  
    

    このコードは、SumPageSizes アプリケーションを実行するメソッドを呼び出し、startButton_Click に制御が戻るとメッセージを表示します。The code calls the method that drives the application, SumPageSizes, and displays a message when control returns to startButton_Click.

  3. 同期ソリューションのコードには、次の 4 つのメソッドが含まれています。The code for the synchronous solution contains the following four methods:

    • SumPageSizes は、SetUpURLList から Web ページ URL のリストを取得し、GetURLContentsDisplayResults を呼び出して各 URL を処理します。SumPageSizes, which gets a list of webpage URLs from SetUpURLList and then calls GetURLContents and DisplayResults to process each URL.

    • SetUpURLList は、Web アドレスのリストを作成して返します。SetUpURLList, which makes and returns a list of web addresses.

    • GetURLContents は、各 Web サイトのコンテンツをダウンロードし、バイト配列としてそのコンテンツを返します。GetURLContents, which downloads the contents of each website and returns the contents as a byte array.

    • DisplayResults は、各 URL のバイト配列内のバイト数を表示します。DisplayResults, which displays the number of bytes in the byte array for each URL.

    次の 4 つのメソッドをコピーし、それを MainWindow.xaml.cs の startButton_Click イベント ハンドラーの下に貼り付けます。Copy the following four methods, and then paste them under the startButton_Click event handler in MainWindow.xaml.cs:

    private void SumPageSizes()  
    {  
        // Make a list of web addresses.  
        List<string> urlList = SetUpURLList();   
    
        var total = 0;  
        foreach (var url in urlList)  
        {  
            // GetURLContents returns the contents of url as a byte array.  
            byte[] urlContents = GetURLContents(url);  
    
            DisplayResults(url, urlContents);  
    
            // Update the total.  
            total += urlContents.Length;  
        }  
    
        // Display the total count for all of the web addresses.  
        resultsTextBox.Text +=   
            string.Format("\r\n\r\nTotal bytes returned:  {0}\r\n", total);  
    }  
    
    private List<string> SetUpURLList()  
    {  
        var urls = new List<string>   
        {   
            "http://msdn.microsoft.com/library/windows/apps/br211380.aspx",  
            "http://msdn.microsoft.com",  
            "http://msdn.microsoft.com/library/hh290136.aspx",  
            "http://msdn.microsoft.com/library/ee256749.aspx",  
            "http://msdn.microsoft.com/library/hh290138.aspx",  
            "http://msdn.microsoft.com/library/hh290140.aspx",  
            "http://msdn.microsoft.com/library/dd470362.aspx",  
            "http://msdn.microsoft.com/library/aa578028.aspx",  
            "http://msdn.microsoft.com/library/ms404677.aspx",  
            "http://msdn.microsoft.com/library/ff730837.aspx"  
        };  
        return urls;  
    }  
    
    private byte[] GetURLContents(string url)  
    {  
        // The downloaded resource ends up in the variable named content.  
        var content = new MemoryStream();  
    
        // Initialize an HttpWebRequest for the current URL.  
        var webReq = (HttpWebRequest)WebRequest.Create(url);  
    
        // Send the request to the Internet resource and wait for  
        // the response.  
        // Note: you can't use HttpWebRequest.GetResponse in a Windows Store app.  
        using (WebResponse response = webReq.GetResponse())  
        {  
            // Get the data stream that is associated with the specified URL.  
            using (Stream responseStream = response.GetResponseStream())  
            {  
                // Read the bytes in responseStream and copy them to content.    
                responseStream.CopyTo(content);  
            }  
        }  
    
        // Return the result as a byte array.  
        return content.ToArray();  
    }  
    
    private void DisplayResults(string url, byte[] content)  
    {  
        // Display the length of each website. The string format   
        // is designed to be used with a monospaced font, such as  
        // Lucida Console or Global Monospace.  
        var bytes = content.Length;  
        // Strip off the "http://".  
        var displayURL = url.Replace("http://", "");  
        resultsTextBox.Text += string.Format("\n{0,-58} {1,8}", displayURL, bytes);  
    }  
    

同期ソリューションをテストするにはTo test the synchronous solution

  1. F5 キーを押してプログラムを実行し、 [Start] を複数回クリックします。Choose the F5 key to run the program, and then choose the Start button.

    次の一覧のような出力が表示されます。Output that resembles the following list should appear.

    msdn.microsoft.com/library/windows/apps/br211380.aspx        383832  
    msdn.microsoft.com                                            33964  
    msdn.microsoft.com/library/hh290136.aspx               225793  
    msdn.microsoft.com/library/ee256749.aspx               143577  
    msdn.microsoft.com/library/hh290138.aspx               237372  
    msdn.microsoft.com/library/hh290140.aspx               128279  
    msdn.microsoft.com/library/dd470362.aspx               157649  
    msdn.microsoft.com/library/aa578028.aspx               204457  
    msdn.microsoft.com/library/ms404677.aspx               176405  
    msdn.microsoft.com/library/ff730837.aspx               143474  
    
    Total bytes returned:  1834802  
    
    Control returned to startButton_Click.  
    

    カウントの表示には数秒かかる点に注意してください。Notice that it takes a few seconds to display the counts. その間、要求されたリソースのダウンロードが完了するまで UI スレッドがブロックされます。During that time, the UI thread is blocked while it waits for requested resources to download. このため、[Start] ボタンのクリック後は、表示ウィンドウの移動、最大化、最小化のほか、閉じることさえできなくなります。As a result, you can't move, maximize, minimize, or even close the display window after you choose the Start button. バイト カウントの表示が開始するまでは、これらの操作を実行しても失敗します。These efforts fail until the byte counts start to appear. Web サイトが応答していない場合、どのサイトに問題があるのかを示す情報は表示されません。If a website isn’t responding, you have no indication of which site failed. 待つのをやめて、プログラムを閉じることさえ難しい状態になります。It is difficult even to stop waiting and close the program.

GetURLContents を非同期メソッドに変換するにはTo convert GetURLContents to an asynchronous method

  1. 同期ソリューションを非同期ソリューションに変換する際に、最初に取りかかるのに最適な場所は、GetURLContents 内です。その理由は、HttpWebRequestGetResponse メソッドおよび StreamCopyTo メソッドへの呼び出しで、アプリケーションが Web にアクセスするためです。To convert the synchronous solution to an asynchronous solution, the best place to start is in GetURLContents because the calls to the HttpWebRequest method GetResponse and to the Stream method CopyTo are where the application accesses the web. .NET Framework には両方のメソッドの非同期バージョンが用意されているため、変換は簡単です。The .NET Framework makes the conversion easy by supplying asynchronous versions of both methods.

    GetURLContents で使用されているメソッドの詳細については、「WebRequest」を参照してください。For more information about the methods that are used in GetURLContents, see WebRequest.

    注意

    このチュートリアルの手順に従っていると、いくつかのコンパイラ エラーが表示されます。As you follow the steps in this walkthrough, several compiler errors appear. これらのエラーは無視することで、チュートリアルを続行できます。You can ignore them and continue with the walkthrough.

    GetURLContents の 3 行目で呼び出されるメソッドを、GetResponse から、非同期でタスク ベースの GetResponseAsync メソッドに変更します。Change the method that's called in the third line of GetURLContents from GetResponse to the asynchronous, task-based GetResponseAsync method.

    using (WebResponse response = webReq.GetResponseAsync())  
    
  2. GetResponseAsync は、Task<TResult> を返します。GetResponseAsync returns a Task<TResult>. この場合、タスク戻り変数TResult の型は WebResponse です。In this case, the task return variable, TResult, has type WebResponse. このタスクは、要求されたデータのダウンロードが完了し、タスクが最後まで実行された後に、実際の WebResponse オブジェクトを生成するという約束です。The task is a promise to produce an actual WebResponse object after the requested data has been downloaded and the task has run to completion.

    タスクから WebResponse 値を取得するには、次のコードに示すように、await (C#) 演算子を GetResponseAsync への呼び出しに適用します。To retrieve the WebResponse value from the task, apply an await operator to the call to GetResponseAsync, as the following code shows.

    using (WebResponse response = await webReq.GetResponseAsync())  
    

    await 演算子は、現在のメソッド、GetURLContents の実行を、待機しているタスクが完了するまで中断します。The await operator suspends the execution of the current method, GetURLContents, until the awaited task is complete. その間、現在のメソッドの呼び出し元に制御が戻されます。In the meantime, control returns to the caller of the current method. この例では、現在のメソッドが GetURLContents で、呼び出し元が SumPageSizes です。In this example, the current method is GetURLContents, and the caller is SumPageSizes. タスクが完了すると、約束されていた WebResponse オブジェクトが完了したタスクの値として生成され、変数 response に割り当てられます。When the task is finished, the promised WebResponse object is produced as the value of the awaited task and assigned to the variable response.

    上記のステートメントは、動作を明確にするため、次の 2 つのステートメントに分割できます。The previous statement can be separated into the following two statements to clarify what happens.

    //Task<WebResponse> responseTask = webReq.GetResponseAsync();  
    //using (WebResponse response = await responseTask)  
    

    webReq.GetResponseAsync への呼び出しによって、Task(Of WebResponse) または Task<WebResponse> が返されます。The call to webReq.GetResponseAsync returns a Task(Of WebResponse) or Task<WebResponse>. その後、WebResponse 値を取得するため、タスクに await 演算子が適用されます。Then an await operator is applied to the task to retrieve the WebResponse value.

    非同期メソッドにタスクの完了に依存しない処理がある場合、メソッドはこれら 2 つのステートメントの間、つまり非同期メソッドへの呼び出しから、await 演算子の適用までの間にその処理を続行することができます。If your async method has work to do that doesn’t depend on the completion of the task, the method can continue with that work between these two statements, after the call to the async method and before the await operator is applied. この例については、「方法: Async と Await を使用して複数の Web 要求を並列実行する (C#)」および「方法: Task.WhenAll を使用して AsyncWalkthrough を拡張する (C#)」を参照してください。For examples, see How to: Make Multiple Web Requests in Parallel by Using async and await (C#) and How to: Extend the async Walkthrough by Using Task.WhenAll (C#).

  3. 前の手順で await 演算子を追加したため、コンパイラ エラーが発生します。Because you added the await operator in the previous step, a compiler error occurs. この演算子は、async 修飾子でマークされているメソッドでのみ使用できます。The operator can be used only in methods that are marked with the async modifier. CopyTo への呼び出しを CopyToAsync への呼び出しに置き換える変換手順を繰り返す間は、エラーを無視してください。Ignore the error while you repeat the conversion steps to replace the call to CopyTo with a call to CopyToAsync.

    • 呼び出されるメソッドの名前を CopyToAsync に変更します。Change the name of the method that’s called to CopyToAsync.

    • CopyTo または CopyToAsync メソッドは、その引数 content にバイトをコピーし、意味のある値は返しません。The CopyTo or CopyToAsync method copies bytes to its argument, content, and doesn’t return a meaningful value. 同期バージョンでは、CopyTo への呼び出しは値を返さない単純なステートメントです。In the synchronous version, the call to CopyTo is a simple statement that doesn't return a value. 非同期バージョンでは、CopyToAsyncTask を返します。The asynchronous version, CopyToAsync, returns a Task. タスクは "Task(void)" のように機能し、メソッドを待機できるようにします。The task functions like "Task(void)" and enables the method to be awaited. 次のコードに示すように、Await または await を、CopyToAsync への呼び出しに適用します。Apply Await or await to the call to CopyToAsync, as the following code shows.

      await responseStream.CopyToAsync(content);  
      

      上記のステートメントでは、次の 2 行のコードを省略しています。The previous statement abbreviates the following two lines of code.

      // CopyToAsync returns a Task, not a Task<T>.  
      //Task copyTask = responseStream.CopyToAsync(content);  
      
      // When copyTask is completed, content contains a copy of  
      // responseStream.  
      //await copyTask;  
      
  4. GetURLContents 内で必要な作業として残っているのは、メソッド シグネチャの調整のみです。All that remains to be done in GetURLContents is to adjust the method signature. await 演算子は、async 修飾子でマークされているメソッドでのみ使用できます。You can use the await operator only in methods that are marked with the async modifier. 次のコードに示すように、修飾子を追加し、メソッドを非同期メソッドとしてマークします。Add the modifier to mark the method as an async method, as the following code shows.

    private async byte[] GetURLContents(string url)  
    
  5. C# での非同期メソッドの戻り値の型は、TaskTask<TResult>、または void のみを指定できます。The return type of an async method can only be Task, Task<TResult>, or void in C#. 通常、void の戻り値の型は、void を必要とする非同期イベント ハンドラーでのみ使用します。Typically, a return type of void is used only in an async event handler, where void is required. それ以外のケースでは、完成したメソッドに、T 型の値を返す return ステートメントが含まれる場合は Task(T) を使用し、完成したメソッドが意味のある値を返さない場合は Task を使用します。In other cases, you use Task(T) if the completed method has a return statement that returns a value of type T, and you use Task if the completed method doesn’t return a meaningful value. 戻り値の型 Task は、"Task(void)" を意味するものと考えることができます。You can think of the Task return type as meaning "Task(void)."

    詳しくは、「非同期の戻り値の型 (C#)」をご覧ください。For more information, see Async Return Types (C#).

    メソッド GetURLContents には return ステートメントがあり、このステートメントはバイト配列を返します。Method GetURLContents has a return statement, and the statement returns a byte array. そのため、非同期バージョンの戻り値の型は Task(T) であり、T はバイト配列です。Therefore, the return type of the async version is Task(T), where T is a byte array. メソッド シグネチャに、次の変更を加えます。Make the following changes in the method signature:

    • 戻り値の型を Task<byte[]> に変更します。Change the return type to Task<byte[]>.

    • 規則により、非同期メソッドは "Async" で終わる名前を持つことになっているため、メソッドの名前を GetURLContentsAsync に変更します。By convention, asynchronous methods have names that end in "Async," so rename the method GetURLContentsAsync.

    これらの変更を次のコードに示します。The following code shows these changes.

    private async Task<byte[]> GetURLContentsAsync(string url)  
    

    このいくつかの変更によって、GetURLContents の非同期メソッドへの変換が完了しました。With those few changes, the conversion of GetURLContents to an asynchronous method is complete.

SumPageSizes を非同期メソッドに変換するにはTo convert SumPageSizes to an asynchronous method

  1. SumPageSizes に対して、前述した手順を繰り返します。Repeat the steps from the previous procedure for SumPageSizes. まずは、GetURLContents への呼び出しを非同期呼び出しに変更します。First, change the call to GetURLContents to an asynchronous call.

    • 呼び出されるメソッドの名前を GetURLContents から GetURLContentsAsync に変更します (まだ変更していない場合)。Change the name of the method that’s called from GetURLContents to GetURLContentsAsync, if you haven't already done so.

    • バイト配列値を取得するために、await を、GetURLContentsAsync が返すタスクに適用します。Apply await to the task that GetURLContentsAsync returns to obtain the byte array value.

    これらの変更を次のコードに示します。The following code shows these changes.

    byte[] urlContents = await GetURLContentsAsync(url);  
    

    上記の割り当てでは、次の 2 行のコードを省略しています。The previous assignment abbreviates the following two lines of code.

    // GetURLContentsAsync returns a Task<T>. At completion, the task  
    // produces a byte array.  
    //Task<byte[]> getContentsTask = GetURLContentsAsync(url);  
    //byte[] urlContents = await getContentsTask;  
    
  2. メソッドのシグネチャに、次の変更を加えます。Make the following changes in the method's signature:

    • メソッドを async 修飾子でマークします。Mark the method with the async modifier.

    • メソッド名に "Async" を追加します。Add "Async" to the method name.

    • 今回、タスク戻り変数の T がない理由は、SumPageSizesAsync が T のための値を返さないからです (メソッドに return ステートメントがありません)。ただし、メソッドは待機可能になるために Task を返す必要があります。There is no task return variable, T, this time because SumPageSizesAsync doesn’t return a value for T. (The method has no return statement.) However, the method must return a Task to be awaitable. そのため、メソッドの戻り値の型を void から Task に変更します。Therefore, change the return type of the method from void to Task.

    これらの変更を次のコードに示します。The following code shows these changes.

    private async Task SumPageSizesAsync()  
    

    SumPageSizes から SumPageSizesAsync への変換が完了しました。The conversion of SumPageSizes to SumPageSizesAsync is complete.

startButton_Click を非同期メソッドに変換するにはTo convert startButton_Click to an asynchronous method

  1. イベント ハンドラーで、呼び出されるメソッドの名前を SumPageSizes から SumPageSizesAsync に変更します (まだ変更していない場合)。In the event handler, change the name of the called method from SumPageSizes to SumPageSizesAsync, if you haven’t already done so.

  2. SumPageSizesAsync は非同期メソッドであるため、結果を待機するイベント ハンドラーのコードを変更します。Because SumPageSizesAsync is an async method, change the code in the event handler to await the result.

    SumPageSizesAsync への呼び出しは、GetURLContentsAsyncCopyToAsync への呼び出しに似ています。The call to SumPageSizesAsync mirrors the call to CopyToAsync in GetURLContentsAsync. この呼び出しによって、Task(T) ではなく Task が返されます。The call returns a Task, not a Task(T).

    前述した手順と同様に、1 つまたは 2 つのステートメントを使用して、呼び出しを変換できます。As in previous procedures, you can convert the call by using one statement or two statements. これらの変更を次のコードに示します。The following code shows these changes.

    // One-step async call.  
    await SumPageSizesAsync();  
    
    // Two-step async call.  
    //Task sumTask = SumPageSizesAsync();  
    //await sumTask;  
    
  3. 誤って操作が再入することを避けるために、次のステートメントを startButton_Click の先頭に追加して [Start] ボタンを無効にします。To prevent accidentally reentering the operation, add the following statement at the top of startButton_Click to disable the Start button.

    // Disable the button until the operation is complete.  
    startButton.IsEnabled = false;  
    

    イベント ハンドラーの末尾で、ボタンを再び有効にできます。You can reenable the button at the end of the event handler.

    // Reenable the button in case you want to run the operation again.  
    startButton.IsEnabled = true;  
    

    再入について詳しくは、「非同期アプリにおける再入の処理 (C#)」をご覧ください。For more information about reentrancy, see Handling Reentrancy in Async Apps (C#).

  4. 最後に、async 修飾子を宣言に追加し、イベント ハンドラーが SumPagSizesAsync を待機できるようにします。Finally, add the async modifier to the declaration so that the event handler can await SumPagSizesAsync.

    private async void startButton_Click(object sender, RoutedEventArgs e)  
    

    通常、イベント ハンドラーの名前は変更されません。Typically, the names of event handlers aren’t changed. 戻り値の型が Task に変更されていない理由は、イベント ハンドラーが void を返す必要があるためです。The return type isn’t changed to Task because event handlers must return void.

    同期処理から非同期処理へのプロジェクトの変換が完了しました。The conversion of the project from synchronous to asynchronous processing is complete.

非同期ソリューションをテストするにはTo test the asynchronous solution

  1. F5 キーを押してプログラムを実行し、 [Start] を複数回クリックします。Choose the F5 key to run the program, and then choose the Start button.

  2. 同期ソリューションの出力に似た出力が表示されます。Output that resembles the output of the synchronous solution should appear. ただし、次の相違点に注意してください。However, notice the following differences.

    • 処理の完了後に、すべての結果が同時に表示されることはありません。The results don’t all occur at the same time, after the processing is complete. たとえば、両方のプログラムの startButton_Click には、テキスト ボックスをクリアする行が含まれています。For example, both programs contain a line in startButton_Click that clears the text box. この目的は、実行ごとにテキスト ボックスをクリアすることです。1 つの結果セットが表示された後に、もう一度 [Start] ボタンをクリックすると、テキスト ボックスがクリアされます。The intent is to clear the text box between runs if you choose the Start button for a second time, after one set of results has appeared. 同期バージョンでは、2 回目のカウントが表示される直前、ダウンロードが完了して UI スレッドが他の処理を実行できる状態になったときにテキスト ボックスがクリアされます。In the synchronous version, the text box is cleared just before the counts appear for the second time, when the downloads are completed and the UI thread is free to do other work. 非同期バージョンでは、[Start] ボタンをクリックした直後にテキスト ボックスがクリアされます。In the asynchronous version, the text box clears immediately after you choose the Start button.

    • 最も重要な点は、ダウンロード中に UI スレッドがブロックされないことです。Most importantly, the UI thread isn’t blocked during the downloads. Web リソースをダウンロード、カウント、および表示している間に、ウィンドウの移動やサイズ変更を行うことができます。You can move or resize the window while the web resources are being downloaded, counted, and displayed. いずれかの Web サイトの処理が遅い、または応答しない場合、閉じるボタン (右上隅の赤色のフィールドにある [x]) をクリックすることで、操作を取り消すことができます。If one of the websites is slow or not responding, you can cancel the operation by choosing the Close button (the x in the red field in the upper-right corner).

GetURLContentsAsync メソッドを .NET Framework メソッドに置き換えるにはTo replace method GetURLContentsAsync with a .NET Framework method

  1. .NET Framework 4.5 では、使用できる非同期メソッドが数多く用意されています。The .NET Framework 4.5 provides many async methods that you can use. その 1 つである、HttpClientGetByteArrayAsync(String) メソッドは、このチュートリアルに必要な処理だけを実行します。One of them, the HttpClient method GetByteArrayAsync(String), does just what you need for this walkthrough. これを、前述の手順で作成した GetURLContentsAsync メソッドの代わりに使用できます。You can use it instead of the GetURLContentsAsync method that you created in an earlier procedure.

    まずは、SumPageSizesAsync メソッドに HttpClient オブジェクトを作成します。The first step is to create an HttpClient object in method SumPageSizesAsync. 次の宣言をメソッドの先頭に追加します。Add the following declaration at the start of the method.

    // Declare an HttpClient object and increase the buffer size. The  
    // default buffer size is 65,536.  
    HttpClient client =  
        new HttpClient() { MaxResponseContentBufferSize = 1000000 };  
    
  2. SumPageSizesAsync, で、GetURLContentsAsync メソッドへの呼び出しを HttpClient メソッドへの呼び出しに置き換えます。In SumPageSizesAsync, replace the call to your GetURLContentsAsync method with a call to the HttpClient method.

    byte[] urlContents = await client.GetByteArrayAsync(url);  
    
  3. 記述した GetURLContentsAsync メソッドを削除するかコメント アウトします。Remove or comment out the GetURLContentsAsync method that you wrote.

  4. F5 キーを押してプログラムを実行し、 [Start] を複数回クリックします。Choose the F5 key to run the program, and then choose the Start button.

    このバージョンのプロジェクトの動作は、「非同期ソリューションをテストするには」の手順で説明している動作と同じですが、さらに少ない手間で作成できます。The behavior of this version of the project should match the behavior that the "To test the asynchronous solution" procedure describes but with even less effort from you.

Example

次のコードには、記述した非同期 GetURLContentsAsync メソッドを使用する、同期ソリューションから非同期ソリューションへの変換例のすべてが含まれています。The following code contains the full example of the conversion from a synchronous to an asynchronous solution by using the asynchronous GetURLContentsAsync method that you wrote. この例は、元の同期ソリューションと非常によく似ています。Notice that it strongly resembles the original, synchronous solution.

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
using System.Threading.Tasks;  
using System.Windows;  
using System.Windows.Controls;  
using System.Windows.Data;  
using System.Windows.Documents;  
using System.Windows.Input;  
using System.Windows.Media;  
using System.Windows.Media.Imaging;  
using System.Windows.Navigation;  
using System.Windows.Shapes;  

// Add the following using directives, and add a reference for System.Net.Http.  
using System.Net.Http;  
using System.IO;  
using System.Net;  

namespace AsyncExampleWPF  
{  
    public partial class MainWindow : Window  
    {  
        public MainWindow()  
        {  
            InitializeComponent();  
        }  

        private async void startButton_Click(object sender, RoutedEventArgs e)  
        {  
            // Disable the button until the operation is complete.  
            startButton.IsEnabled = false;  

            resultsTextBox.Clear();  

            // One-step async call.  
            await SumPageSizesAsync();  

            // Two-step async call.  
            //Task sumTask = SumPageSizesAsync();  
            //await sumTask;  

            resultsTextBox.Text += "\r\nControl returned to startButton_Click.\r\n";  

            // Reenable the button in case you want to run the operation again.  
            startButton.IsEnabled = true;  
        }  

        private async Task SumPageSizesAsync()  
        {  
            // Make a list of web addresses.  
            List<string> urlList = SetUpURLList();  

            var total = 0;  

            foreach (var url in urlList)  
            {  
                byte[] urlContents = await GetURLContentsAsync(url);  

                // The previous line abbreviates the following two assignment statements.  

                // GetURLContentsAsync returns a Task<T>. At completion, the task  
                // produces a byte array.  
                //Task<byte[]> getContentsTask = GetURLContentsAsync(url);  
                //byte[] urlContents = await getContentsTask;  

                DisplayResults(url, urlContents);  

                // Update the total.            
                total += urlContents.Length;  
            }  
            // Display the total count for all of the websites.  
            resultsTextBox.Text +=  
                string.Format("\r\n\r\nTotal bytes returned:  {0}\r\n", total);  
        }  

        private List<string> SetUpURLList()  
        {  
            List<string> urls = new List<string>   
            {   
                "http://msdn.microsoft.com/library/windows/apps/br211380.aspx",  
                "http://msdn.microsoft.com",  
                "http://msdn.microsoft.com/library/hh290136.aspx",  
                "http://msdn.microsoft.com/library/ee256749.aspx",  
                "http://msdn.microsoft.com/library/hh290138.aspx",  
                "http://msdn.microsoft.com/library/hh290140.aspx",  
                "http://msdn.microsoft.com/library/dd470362.aspx",  
                "http://msdn.microsoft.com/library/aa578028.aspx",  
                "http://msdn.microsoft.com/library/ms404677.aspx",  
                "http://msdn.microsoft.com/library/ff730837.aspx"  
            };  
            return urls;  
        }  

        private async Task<byte[]> GetURLContentsAsync(string url)  
        {  
            // The downloaded resource ends up in the variable named content.  
            var content = new MemoryStream();  

            // Initialize an HttpWebRequest for the current URL.  
            var webReq = (HttpWebRequest)WebRequest.Create(url);  

            // Send the request to the Internet resource and wait for  
            // the response.                  
            using (WebResponse response = await webReq.GetResponseAsync())  

            // The previous statement abbreviates the following two statements.  

            //Task<WebResponse> responseTask = webReq.GetResponseAsync();  
            //using (WebResponse response = await responseTask)  
            {  
                // Get the data stream that is associated with the specified url.  
                using (Stream responseStream = response.GetResponseStream())  
                {  
                    // Read the bytes in responseStream and copy them to content.   
                    await responseStream.CopyToAsync(content);  

                    // The previous statement abbreviates the following two statements.  

                    // CopyToAsync returns a Task, not a Task<T>.  
                    //Task copyTask = responseStream.CopyToAsync(content);  

                    // When copyTask is completed, content contains a copy of  
                    // responseStream.  
                    //await copyTask;  
                }  
            }  
            // Return the result as a byte array.  
            return content.ToArray();  
        }  

        private void DisplayResults(string url, byte[] content)  
        {  
            // Display the length of each website. The string format   
            // is designed to be used with a monospaced font, such as  
            // Lucida Console or Global Monospace.  
            var bytes = content.Length;  
            // Strip off the "http://".  
            var displayURL = url.Replace("http://", "");  
            resultsTextBox.Text += string.Format("\n{0,-58} {1,8}", displayURL, bytes);  
        }  
    }  
}  

次のコードには、HttpClientGetByteArrayAsync メソッドを使用するソリューション例のすべてが含まれています。The following code contains the full example of the solution that uses the HttpClient method, GetByteArrayAsync.

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Text;  
using System.Threading.Tasks;  
using System.Windows;  
using System.Windows.Controls;  
using System.Windows.Data;  
using System.Windows.Documents;  
using System.Windows.Input;  
using System.Windows.Media;  
using System.Windows.Media.Imaging;  
using System.Windows.Navigation;  
using System.Windows.Shapes;  

// Add the following using directives, and add a reference for System.Net.Http.  
using System.Net.Http;  
using System.IO;  
using System.Net;  

namespace AsyncExampleWPF  
{  
    public partial class MainWindow : Window  
    {  
        public MainWindow()  
        {  
            InitializeComponent();  
        }  

        private async void startButton_Click(object sender, RoutedEventArgs e)  
        {  
            resultsTextBox.Clear();  

            // Disable the button until the operation is complete.  
            startButton.IsEnabled = false;  

            // One-step async call.  
            await SumPageSizesAsync();  

            //// Two-step async call.  
            //Task sumTask = SumPageSizesAsync();  
            //await sumTask;  

            resultsTextBox.Text += "\r\nControl returned to startButton_Click.\r\n";  

            // Reenable the button in case you want to run the operation again.  
            startButton.IsEnabled = true;  
        }  

        private async Task SumPageSizesAsync()  
        {  
            // Declare an HttpClient object and increase the buffer size. The  
            // default buffer size is 65,536.  
            HttpClient client =  
                new HttpClient() { MaxResponseContentBufferSize = 1000000 };  

            // Make a list of web addresses.  
            List<string> urlList = SetUpURLList();  

            var total = 0;  

            foreach (var url in urlList)  
            {  
                // GetByteArrayAsync returns a task. At completion, the task  
                // produces a byte array.  
                byte[] urlContents = await client.GetByteArrayAsync(url);                 

                // The following two lines can replace the previous assignment statement.  
                //Task<byte[]> getContentsTask = client.GetByteArrayAsync(url);  
                //byte[] urlContents = await getContentsTask;  

                DisplayResults(url, urlContents);  

                // Update the total.  
                total += urlContents.Length;  
            }  

            // Display the total count for all of the websites.  
            resultsTextBox.Text +=  
                string.Format("\r\n\r\nTotal bytes returned:  {0}\r\n", total);  
        }  

        private List<string> SetUpURLList()  
        {  
            List<string> urls = new List<string>   
            {   
                "http://msdn.microsoft.com/library/windows/apps/br211380.aspx",  
                "http://msdn.microsoft.com",  
                "http://msdn.microsoft.com/library/hh290136.aspx",  
                "http://msdn.microsoft.com/library/ee256749.aspx",  
                "http://msdn.microsoft.com/library/hh290138.aspx",  
                "http://msdn.microsoft.com/library/hh290140.aspx",  
                "http://msdn.microsoft.com/library/dd470362.aspx",  
                "http://msdn.microsoft.com/library/aa578028.aspx",  
                "http://msdn.microsoft.com/library/ms404677.aspx",  
                "http://msdn.microsoft.com/library/ff730837.aspx"  
            };  
            return urls;  
        }  

        private void DisplayResults(string url, byte[] content)  
        {  
            // Display the length of each website. The string format   
            // is designed to be used with a monospaced font, such as  
            // Lucida Console or Global Monospace.  
            var bytes = content.Length;  
            // Strip off the "http://".  
            var displayURL = url.Replace("http://", "");  
            resultsTextBox.Text += string.Format("\n{0,-58} {1,8}", displayURL, bytes);  
        }  
    }  
}  

参照See Also