いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

WCF入門-010 (基本的なサンプル, 非同期処理)


今回は、サービスメソッドの非同期処理について。


WCFでは、「サービス参照の追加」を利用してクライアントプロキシを作成する際に
非同期処理が行えるようにできるオプションがあります。


このオプションを設定して、クライアントプロキシを作成すると
IAsyncResultを利用したおなじみの非同期処理メソッドが作成されます。


オプションは、「サービス参照の追加」ダイアログにて「非同期操作の生成」チェックボックス
をチェックすれば作成されます。

呼び出し方法は、いつものやり方です。


以下、サンプルです。
まず、サービス定義。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace Gsf.Samples.WCF
{
    [ServiceContract]
    public interface IMyService
    {
        [OperationContract]
        string GetData(int value);
    }
}
using System;
using System.Collections.Generic;
using System.Linq;

namespace Gsf.Samples.WCF
{
    public class MyService : IMyService
    {
        public string GetData(int value)
        {
            System.Threading.Thread.Sleep(TimeSpan.FromSeconds(2));
            
            return string.Format("you enter: {0}", value);
        }
    }
}


次にホストアプリ。

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;

namespace Gsf.Samples.WCF
{
    class Program
    {
        static void Main()
        {
            using (var host = new ServiceHost(typeof(MyService)))
            {
                host.Open();

                Console.WriteLine("サービスが開始されました。");
                Console.WriteLine("press <ENTER> to exit...");
                Console.ReadLine();

                host.Close();
            }
        }
    }
}

ホスト側のアプリケーション構成ファイル。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="Gsf.Samples.WCF.MyService">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8090/WCFSample010/MyService"/>
          </baseAddresses>
        </host>
        <endpoint address=""
                  binding="basicHttpBinding"
                  contract="Gsf.Samples.WCF.IMyService" />
      </service>
    </services>
  </system.serviceModel>
</configuration>


次にクライアントアプリ。
クライアントアプリのボタンをクリックすると内部で
非同期処理が実行されます。コールバックにて、画面のラベルに
結果を表示するようになっています。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.ServiceModel;
using Client.MyServiceRef;

namespace Client
{
    public partial class Form1 : Form
    {
        private int _count;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            lblResult.ResetText();
            ActiveControl = btnCallServiceMethod;

            _count = 100;
        }

        private void btnCallServiceMethod_Click(object sender, EventArgs e)
        {
            var client = new MyServiceClient();
            client.BeginGetData(
                 _count++
                ,GetDataAsyncCallback
                ,client
            );
        }

        private void GetDataAsyncCallback(IAsyncResult ar)
        {
            MyServiceClient client  = (MyServiceClient) ar.AsyncState;            
            Control         control = lblResult;
            Action<string>  action  = UpdateResult;

            string result = string.Empty;
            try
            {
                result = client.EndGetData(ar);
                control.Invoke(action, result);
            }
            catch (CommunicationException ex)
            {
                control.Invoke(action, ex.Message);
                client.Abort();
            }
            finally
            {
                if (client.State != CommunicationState.Closed)
                {
                    client.Close();
                }
            }
        }

        private void UpdateResult(string result)
        {
            lblResult.Text = result;
        }
    }    
}

クライアント側のアプリケーション構成ファイル。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <client>
            <endpoint address="http://localhost:8090/WCFSample010/MyService" 
                      binding="basicHttpBinding" 
                      contract="MyServiceRef.IMyService" />
        </client>
    </system.serviceModel>
</configuration>


実行すると以下のようになります。実際に動かしてみると
ボタンを押下した後、すぐに制御が戻ってきて、結果が返ってくるまで
UIはブロックされずに動作します。



サンプルは以下の場所にアップしてあります。
https://sites.google.com/site/gsfzero1/Home/WCFSample-010.zip?attredirects=0&d=1


================================
過去の記事については、以下のページからご参照下さい。