Uncategorized

ASP.NET WebForms 4.5, WCF 4.5 における非同期 (async) メソッド

環境 :
Visual Studio 2012 Beta

こんにちは。
.NET ラボ で、セッションを聞いていただいた皆様、ありがとうございました。
「Q & A は懇親会で」と思っていたんですが、子供が夕方に高熱を出して、急遽、懇親会の参加ができなくなってしまいました。すみませんでした。

セッションの最後で説明した Web Form と WCF の async メソッドについて、説明が駆け足になりすぎて手順が説明できなかったので、本ブログにて補足しておきます。(主要な話は、「.NET で非同期 (Async) がなぜ重要なのか」 のほうに記載してますので、ゆっくりとお試しください。)

ASP.NET MVC、ASP.NET Web API だけでなく、Web Forms、WCF などについても、下記の通り、非同期に対応しています。

 

ASP.NET Web Forms 4.5 の async メソッド

ASP.NET Web Form でも、Thread Pool を有効活用する async メソッドが構築できますが、説明した通り、ちょっと特殊な書き方になります。

まず、Page ディレクティブに、下記 太字を追加しておきます。

<%@ Page title='' ... Async="true" %>

さらに、Web.config に、以下を記述します。

<configuration>  <appSettings>    . . .    <add      key="aspnet:UseTaskFriendlySynchronizationContext"      value="true" />  </appSettings>  . . .</configuration>

説明した通り、async キーワードを付けて、Page_Load や、Button1_Click などを実装したくなりますが、現 Beta 段階では、こうしたプログラミングは不可能です。従来通り、.NET 4 でサポートされていた Page.RegisterAsyncTask メソッドを使用して、非同期メソッドを登録する必要があります。

ただし、.NET 4.5 では、PageAsyncTask コンストラクタとして、PageAsyncTask(Func<Task> handler) が使えるようになっています。このため、以下の通り、async / await を使ってスッキリと記述できます。

protected void Page_Load(object sender, EventArgs e){  Page.RegisterAsyncTask(new PageAsyncTask(async () =>    {      HttpClient cl = new HttpClient();      HttpResponseMessage res = await cl.GetAsync(@"http://testsite/HeavyPage/");      Label1.Text = res.ToString();    }));}

 

WCF 4.5 の async メソッド

こちら、実は、Parallel Programming Team のブログ に簡単に書かれているのですが (MSDN には、まだ載っていないようです)、.NET Framework 4.5 の WCF では Task を返すことが可能になっています。
このため、ASP.NET MVC などと同じく、非同期 (async) を使用した Thread Pool の有効活用が容易になっています。(ちなみに、WCF では、Worker Thread ではなく、Thread Pool の IO Thread が使用されます。)

下記のコードは、.NET 4 の WCF で可能だった非同期パターン (AsyncPattern = true) のプログラミング スタイルではありません。以前 述べたように、Task を使った同期に近いプログラミング スタイルで、非同期処理によって、スレッドの占有を無くす効率的なプログラム コードになっています。

[ServiceContract]public interface IService1{    [OperationContract]    Task<string> GetDataAsync();}public class Service1 : IService1{public async Task<string> GetDataAsync(){HttpResponseMessage res = await GetHeavyPage();return res.ToString();}private Task<HttpResponseMessage> GetHeavyPage(){HttpClient cl = new HttpClient();return cl.GetAsync(@"http://localhost/HeavyWeb/");}}

上記のメソッドの名称 (GetDataAsync) に注意してください。
WCF 4.5 では、「WCF 4.5 新機能」 で述べたように、クライアント アプリケーションで [サービス参照の追加] (SvcUtil.exe) をおこなうと、非同期用のメソッド (…Async という名前のオペレーション) が構築されます。例えば、「GetData」という名前のオペレーションがサーバーで提供されている場合、クライアント側では GetData と GetDataAsync という 2 つのオペレーションが生成されます。
しかし、上記のサービスを参照追加した場合、クライアント側で「GetDataAsyncAsync」が生成されるのではなく、「GetData」と「GetDataAsync」という 2 つのオペレーションが提供されます。注意していただきたいのは、これら (GetData と GetDataAsync) は、いずれも、クライアント側における同期 / 非同期パターンのオペレーションであり、いずれのオペレーションを使用しても、サーバー側では、スレッドの無駄使いをしない効率的な非同期動作となります。(サーバー側とクライアント側を混同しないように注意してください。)

なお、WCF Data Services は、ご存じの通り、WCF の REST (WebHttp) を使って実装されています。この WCF Data Services で動作を確認したところ、残念ながら、検索している間、Thread Pool の Thread (IO Thread) がずっと握られていました。 (.NET 4.5 Beta で確認。) 少なくとも Beta 段階では、WCF Data Services で、この非同期の仕組みは使われていないようです。(このため、WCF Data Services で、あまり時間のかかるクエリーは実行しないようにしましょう。スレッドがどんどん溜まっていく可能性があります。)

 

ということで、.NET Framework 4.5 における サーバー側の 非同期メソッドの対応状況をまとめると、以下のような感じになります。

ASP.NET WebFormsOK
ASP.NET MVCOK
ASP.NET Web APIOK
WebSocketOK
WCFOK
WCF Data ServicesN/A

 

Categories: Uncategorized

Tagged as:

3 replies»

  1. 初めまして
    現在、下記サイトを作っているのですが、
    http://www.wiredblogs.com/landing.aspx
    人が足らないため、協力者を求めています。
    このサイトに関しては、google mapのAPIの知識、デザイン作成が必要となっております。
    もし、可能であれば、ご協力をお願いしたいと思って連絡を致しました。
    可能であれば、ご連絡をお願いします。
    マッテオ・マルティーニ
    matteomartini72(at)yahoo(dot)com

    Like

Leave a Reply