WCF Sample 014:OneWayオペレーションを実装するWCFサービスを作成してみる で作成したものとサービスを改良してクライアントの非同期呼び出しを実装します。

確認環境は次のとおり。

  • Windows Vista Enterprise(サービス、クライアント同一マシン)
  • 開発環境 Visual Studio 2008 Professional (英語版)
  • .NET 3.5
  • バインディング wsHttpBinding

1.ソリューションの作成

Visual Studioを起動して空のソリューションを作成します。ソリューション名はWCFSample015としました。

WCF Sample 014:OneWayオペレーションを実装するWCFサービスを作成してみるで作成した次の3つのプロジェクトをWCFSample015を作成したソリューションのフォルダにコピーし、既存のプロジェクトとして追加します。プログラム自体はWCFSample.LongTimeWPFHost以外のソースを再掲します。

  • WCFSample.LongTimeService
  • WCFSample.LongTimeWPFHost
  • WCFSample.LongTImeConsoleClient

WCFSample.LongTimeWPFHostからWCFSample.LongTimeServiceプロジェクトを参照するように設定されていることを確認して下さい。

2.プログラムの修正

2.1 WCFサービスの修正

OneWayメソッドとしないので、WCFSample.LongTimeServiceのHeavyService.cs,IHeavyService.csを開いて、プログラムを修正します。

IHeavyService.csは次のようにOperationContractのOneWayの設定を削除します。

namespace WCFSample.LongTimeService
{
    [ServiceContract(Namespace="http://handcraft.wcfsample.org/2008/05/17", Name="HeavyService")]
    public interface IHeavyService
    {
        /// <summary>
        /// 引数で指定されたミリ秒間スリープする
         /// </summary>
        /// <param name="msec">スリープするミリ秒時間</param>
        [OperationContract()]
        int ProcessHeavyService(int msec);
    }
}

HeavyService.csを変更して、InstanceContextModeをデフォルトに戻します。

namespace WCFSample.LongTimeService
{
    [ServiceBehavior()]
    public class HeavyService : IHeavyService
    {
        #region IHeavyService Members

        public int ProcessHeavyService(int msec)
        {
            System.Threading.Thread.Sleep(msec);
            return msec;
        }

        #endregion
    }
}

2.2 プロキシの再作成

ソリューションをビルドします。Visual Studio 2008 Command Promptを起動して、WCFSample.LongTImeService.dllが作成フォルダまで移動して、次のコマンドを入力し、サービスのメタ情報ファイルを生成します。

svcutil WCFSample.LongTimeService.dll

 

 

続いて、次のコマンドを入力し、メタ情報ファイルからプロキシを作成します。非同期呼び出しを作成するには/asyncオプションを指定します。

svcutil /namespace:*,WCFSample.Client handcraft.wcfsample.org.2008.05.17.wsdl *.xsd  /async /out:Proxy.cs

 

Proxy.csを確認すると、サービスコントラクトに、非同期呼び出し用のBegin+サービスメソッド,End+サービスメソッドが含まれていることが確認できます。作成されたProxy.csをWCFSample.LongTImeConsoleClient プロジェクトフォルダにコピーします。

Visual Studio上でクライアントプロジェクトを右クリック→Add Service Reference...からでも表示されるサービスの参照追加ダイアログから非同期呼び出しを行うプロキシを作成するように設定することができます。

2.3 WCFクライアントの修正

Program.csを開き、次のように非同期メソッドを呼び出すように修正します。接頭辞にBeginのつくサービスメソッドを呼び出すと、メソッドがブロックされずに処理が続行されるようになります。

namespace WCFSample.LongTimeConsoleClient
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("キーを入力して下さい");
            Console.ReadLine();
            try
            {
                HeavyServiceClient proxy = new HeavyServiceClient("DefaultBinding_HeavyService");
                Console.WriteLine("1回目の呼び出し開始");
                //IAsyncResult rs1 = proxy.BeginProcessHeavyService(10000, Callback, proxy); // コールバックを利用する場合
                IAsyncResult rs1 = proxy.BeginProcessHeavyService(10000, null, null);
                Console.WriteLine("1回目の呼び出し完了");
                Console.WriteLine("2回目の呼び出し開始");
                //IAsyncResult rs2 = proxy.BeginProcessHeavyService(20000, Callback, proxy); // コールバックを利用する場合
                IAsyncResult rs2 = proxy.BeginProcessHeavyService(20000, null, null);
                Console.WriteLine("2回目の呼び出し完了");

                Console.WriteLine(proxy.EndProcessHeavyService(rs1));
                Console.WriteLine(proxy.EndProcessHeavyService(rs2));
                proxy.Close();
            }
            catch (Exception ex)
            {
                System.Console.WriteLine(ex.Message);
            }
            Console.WriteLine("プログラムが終了しました。キーを入力してください。");
            Console.ReadLine();
        }
        /// <summary>
        /// コールバックメソッドを使用する場合
        /// </summary>
        /// <param name="ar"></param>
        static void Callback(IAsyncResult ar)
        {
            HeavyServiceClient proxy = ar.AsyncState as HeavyServiceClient;
            Console.WriteLine(proxy.EndProcessHeavyService(ar));
        }
    }
}

2.4 構成ファイルの変更

WCF Sample 014:OneWayオペレーションを実装するWCFサービスを作成してみるではリライアブルセッションをしようするようにしていたので、リライアブルセッションを使用しないように直接修正しました。
ホスト側の構成ファイルを以下のように編集しました。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="LongTimeWSBindingConfig" >
                </binding>
            </wsHttpBinding>
        </bindings>
        <services>
            <service name="WCFSample.LongTimeService.HeavyService">
                <endpoint address="http://localhost:8056/LongTimeService" binding="wsHttpBinding"
                    bindingConfiguration="LongTimeWSBindingConfig" contract="WCFSample.LongTimeService.IHeavyService" />
            </service>
        </services>
    </system.serviceModel>
</configuration>

クライアント側の構成ファイルを以下のように設定します。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
                <binding name="DefaultBinding_HeavyService">
                </binding>
            </wsHttpBinding>
        </bindings>
        <client>
          <endpoint binding="wsHttpBinding" bindingConfiguration="DefaultBinding_HeavyService"
              contract="WCFSample.Client.HeavyService" name="DefaultBinding_HeavyService" address="http://localhost:8056/LongTimeService" >
          </endpoint>
        </client>
    </system.serviceModel>
</configuration>

3 動作確認

デバッグ実行すると2回目呼び出し完了というメッセージがコンソールにすぐに出力され、10秒,20秒後にEndProcessHeavyServiceの返り値が表示され、非同期呼び出しが実行されていることが確認できます。クラインとプログラム中にコメントアウトされているコールバックを使用する場合は、コールバックが完了後にプロキシのCloseメソッドを呼び出す必要があります。