いろいろ備忘録日記

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

WCF入門-007 (基本的なサンプル, 双方向通信(Duplex))


WCFには、3種類の通信方法があります。

  • 要求/応答パターン
  • 一方向通信パターン
  • 双方向通信パターン(非同期)


双方向通信パターンは、文字通りクライアントとサービスの双方で通信を行いあうパターンです。
イメージとしては、クライアントがサービスを呼び出すと、処理がサービス側で行われ
サービス側の処理が完了すると、今度はサービス側からクライアント側のコールバックが呼ばれるイメージです。

双方向通信を行う場合、サービスインタフェースの定義に加えてコールバック用のインタフェースを定義する必要があります。

双方向通信の場合、サービスメソッドとコールバックメソッドのどちらもIsOneWay=trueを設定する必要があります。
(非同期で呼び合うため、IsOneWayを設定する必要がある。)


双方向通信を行うために必要な設定は

  • Callback用のインターフェースを定義
  • CallbackContractの設定
    • ServiceContractにCallbackContractを設定する必要がある。
  • サービスメソッドにIsOneWay=trueを設定
  • コールバックメソッドにIsOneWay=trueを設定
  • クライアント側にてコールバックインターフェースを実装
  • サービスメソッド内にて、OperationContextからコールバックを取得し呼出
  • クライアント側にて、プロキシ作成時にInstanceContextを渡す
  • bindingに双方向通信をサポートしているものを設定 (wsDualHttpBindingなど)


となります。箇条書きにすると多くなりますが
実際、実装するとなると、そんなに大変ではないです。


以下、サンプルです。
まず、コールバックインターフェース定義。

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

namespace Gsf.Samples.WCF
{
    public interface IMyCallback
    {
        [OperationContract(IsOneWay=true)]
        void SendData(string name);
    }
}


つづいて、サービス定義。
CallbackContractを設定する必要がある事に注意。

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

namespace Gsf.Samples.WCF
{
    [ServiceContract(
        Namespace="http://Gsf.Samples.WCF", 
        CallbackContract=typeof(IMyCallback))]
    public interface IMyService
    {
        [OperationContract(IsOneWay=true)]
        void Regist(string name);
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;

namespace Gsf.Samples.WCF
{
    public class MyService : IMyService
    {
        public void Regist(string name)
        {
            Console.Write("[CALL] Regist() => ");

            var context  = OperationContext.Current;
            var callback = context.GetCallbackChannel<IMyCallback>();

            Console.WriteLine("[CALLBACK] SendData();");
            callback.SendData(string.Format("{0}_Callback", name));
        }
    }
}


次にホストアプリ。

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();
            }
        }
    }
}


ホスト側のアプリケーション構成ファイル。
bindingには、双方向通信をサポートしているwsDualHttpBindingを指定しています。

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


次にクライアント側。
コールバックインターフェースを実装しています。
また、Loadイベントにてプロキシオブジェクトを作成していますが
その際に、InstanceContextを生成し渡しています。

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

namespace Gsf.Samples.WCF
{
    public partial class Form1 : Form, MyServiceRef.IMyServiceCallback
    {
        MyServiceRef.MyServiceClient _client;

        public Form1()
        {
            InitializeComponent();

            FormClosing += (s, e) => { _client.Close(); };
        }

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

            // 双方向通信を行う場合、サービス側にコールバックの実装を教える必要がある。
            var context = new InstanceContext(this);
            _client = new MyServiceRef.MyServiceClient(context);
        }

        private void btnCallServiceMethod_Click(object sender, EventArgs e)
        {
            _client.Regist("WCF Study");
        }

        // コールバックの実装
        public void SendData(string name)
        {
            lblResult.Text = name;
        }
    }
}


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

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


実行すると以下のようになります。


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


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